__DEV__ 全局魔法变量
如果你曾经发布过一个 NativeScript 应用,并意识到你的控制台在生产环境中仍然充满了调试日志------那么这篇文章就是为你准备的。
NativeScript 提供了一个方便的全局魔法变量,叫做 __DEV__,它允许你仅在开发期间有条件地运行代码。在本文中,我将向你展示我是如何使用它来添加详细的 API 日志记录,这些日志会自动在生产构建中消失。
问题
当我在我的 NativeScript 应用中调试 API 集成时,我需要看到完整的请求 URL、参数和响应体。所以我到处都加上了 console.log:
typescript
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__为 truens run android→__DEV__为 false- 发布/生产构建 →
__DEV__为 false
更好的是,因为它是在构建时解析的,Vite 的摇树优化(tree-shaking)将完全从你的生产包中移除这些死代码分支。
实践中使用 __DEV__
以下是我如何重构我的 API 工具:
typescript
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 时,我能看到详细的日志:
csharp
[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 文件):
typescript
declare const __DEV__: boolean
declare const __ANDROID__: boolean
declare const __IOS__: boolean
declare const __VISIONOS__: boolean
更多用例
__DEV__ 标志不仅仅用于日志记录。以下是我发现有用的其他一些模式:
在开发中使用模拟数据
typescript
export function getConfig() {
if (__DEV__) {
return {
apiUrl: 'https://staging.example.com/api',
timeout: 30000, // 为了调试而设置更长的超时时间
}
}
return {
apiUrl: 'https://api.example.com',
timeout: 10000,
}
}
开发者工具 / 调试 UI
typescript
// 在你的主应用组件中
if (__DEV__) {
// 显示一个带有设备信息、网络状态等的调试覆盖层
registerDebugOverlay()
}
性能计时
typescript
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
}
在开发期间跳过昂贵的操作
typescript
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 时,构建本质上是这样做的:
javascript
// 之前(源代码)
if (__DEV__) {
console.log('debug info')
}
// 构建后(开发)
if (true) {
console.log('debug info')
}
对于生产环境:
javascript
// 构建后(生产)--- 压缩前
if (false) {
console.log('debug info')
}
// 经过摇树优化/压缩后 --- 完全移除!
死代码被完全消除,所以在生产环境中没有运行时成本。
关键要点
- 使用
__DEV__而不是手动标志或环境变量来进行调试/发布分支 - 它是一个编译时常量------死代码会从生产构建中被摇树优化掉
- 添加 TypeScript 声明以避免类型错误
- 非常适合:调试日志、模拟数据、开发者工具、性能计时
ns debug=__DEV__为 true,ns run/ 发布 =__DEV__为 false
停止在你的代码库中到处留下 // TODO: remove before release 的注释。让构建工具为你完成这项工作。