如何在 NativeScript 中使用 __DEV__ 标志进行更智能的调试日志记录

0 阅读4分钟

__DEV__ 全局魔法变量

如果你曾经发布过一个 NativeScript 应用,并意识到你的控制台在生产环境中仍然充满了调试日志——那么这篇文章就是为你准备的。

NativeScript 提供了一个方便的全局魔法变量,叫做 __DEV__,它允许你仅在开发期间有条件地运行代码。在本文中,我将向你展示我是如何使用它来添加详细的 API 日志记录,这些日志会自动在生产构建中消失。

问题

当我在我的 NativeScript 应用中调试 API 集成时,我需要看到完整的请求 URL、参数和响应体。所以我到处都加上了 console.log

const callApi = (endpoint: string, params: any) => {
  console.log(`POST ${endpoint}`)
  console.log(`params: ${JSON.stringify(params)}`)

  return fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    },
    body: JSON.stringify(params),
  }).then(async (response) => {
    const text = await response.text()
    console.log(`Response: ${response.status} ${text}`)
    return JSON.parse(text)
  })
}

这在调试时效果很好。但我绝对不希望在生产构建中有所有这些日志记录——它很嘈杂,可能会泄露敏感数据,并增加不必要的开销。

我可以在每次在调试和发布之间切换时手动注释/取消注释这些行……但有更好的方法。

解决方案:__DEV__

NativeScript(通过其 Vite 配置)暴露了几个在构建时解析的全局魔法变量:

变量描述
__DEV__在开发模式下为 true,在生产模式下为 false
__ANDROID__在为 Android 构建时为 true
__IOS__在为 iOS 构建时为 true
__VISIONOS__在为 visionOS 构建时为 true

关键在于,__DEV__ 是一个编译时常量,而不是运行时检查。这意味着:

  • ns debug android__DEV__ 为 true
  • ns run android__DEV__ 为 false
  • 发布/生产构建 → __DEV__ 为 false

更好的是,因为它是在构建时解析的,Vite 的摇树优化(tree-shaking)将完全从你的生产包中移除这些死代码分支。

实践中使用 __DEV__

以下是我如何重构我的 API 工具:

const callApi = (endpoint: string, params: any) => {
  if (__DEV__) {
    console.log(`[API] >>> POST ${endpoint}`)
    console.log(`[API] >>> params: ${JSON.stringify(params)}`)
  }

  return fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    },
    body: JSON.stringify(params),
  }).then(async (response) => {
    // 在生产环境中,直接解析 JSON(更快,没有额外的内存分配)
    if (!__DEV__) return response.json()

    // 在开发环境中,首先读取原始文本以进行调试
    const text = await response.text()
    console.log(`[API] <<< ${response.status} ${text.substring(0, 500)}`)
    return JSON.parse(text)
  })
}

现在当我运行 ns debug android 时,我能看到详细的日志:

[API] >>> POST https://api.example.com/health_check
[API] >>> params: {"device_id":"abc123","secret":"xyz789"}
[API] <<< 200 {"status":"ok"}

而当我运行 ns run android 或构建发布版时——零噪音。日志记录代码甚至不存在于包中。

TypeScript 设置

如果你正在使用 TypeScript(你应该使用),你可能会在 __DEV__ 下看到波浪线,因为编译器不知道它。通过添加类型声明来修复这个问题。

创建或更新你的 references.d.ts(或包含在你项目中的任何 .d.ts 文件):

declare const __DEV__: boolean
declare const __ANDROID__: boolean
declare const __IOS__: boolean
declare const __VISIONOS__: boolean

更多用例

__DEV__ 标志不仅仅用于日志记录。以下是我发现有用的其他一些模式:

在开发中使用模拟数据

export function getConfig() {
  if (__DEV__) {
    return {
      apiUrl: 'https://staging.example.com/api',
      timeout: 30000, // 为了调试而设置更长的超时时间
    }
  }
  return {
    apiUrl: 'https://api.example.com',
    timeout: 10000,
  }
}

开发者工具 / 调试 UI

// 在你的主应用组件中
if (__DEV__) {
  // 显示一个带有设备信息、网络状态等的调试覆盖层
  registerDebugOverlay()
}

性能计时

export async function fetchData() {
  let start: number
  if (__DEV__) {
    start = Date.now()
  }

  const result = await api.getData()

  if (__DEV__) {
    console.log(`fetchData took ${Date.now() - start!}ms`)
  }

  return result
}

在开发期间跳过昂贵的操作

if (__DEV__) {
  // 在开发期间跳过实际的短信发送
  console.log(`[DEV] Would send SMS to ${phoneNumber}: ${message}`)
  return { success: true }
}

return sendRealSms(phoneNumber, message)

内部工作原理

NativeScript 使用 Vite 作为其构建工具。在 NativeScript Vite 插件中,__DEV__ 使用 Vite 的 define 选项定义,该选项在构建时执行全局字符串替换。

当你运行 ns debug 时,构建本质上是这样做的:

// 之前(源代码)
if (__DEV__) {
  console.log('debug info')
}

// 构建后(开发)
if (true) {
  console.log('debug info')
}

对于生产环境:

// 构建后(生产)— 压缩前
if (false) {
  console.log('debug info')
}

// 经过摇树优化/压缩后 — 完全移除!

死代码被完全消除,所以在生产环境中没有运行时成本。

关键要点
  • 使用 __DEV__ 而不是手动标志或环境变量来进行调试/发布分支
  • 它是一个编译时常量——死代码会从生产构建中被摇树优化掉
  • 添加 TypeScript 声明以避免类型错误
  • 非常适合:调试日志、模拟数据、开发者工具、性能计时
  • ns debug = __DEV__ 为 true,ns run / 发布 = __DEV__ 为 false

停止在你的代码库中到处留下 // TODO: remove before release 的注释。让构建工具为你完成这项工作。

newbiescripter.com/how-to-use-…