--define
标志允许您声明可静态分析的常量和全局变量。它将 JavaScript 或 TypeScript 文件中标识符或属性的所有用法替换为常量值。此功能在运行时以及 bun build
中均受支持。这有点类似于 C/C++ 中的 #define
,但用于 JavaScript。
bun --define process.env.NODE_ENV="'production'" src/index.ts # Runtime
bun build --define process.env.NODE_ENV="'production'" src/index.ts # Build
Bun 使用这些静态已知的值进行死代码消除和其他优化。
if (process.env.NODE_ENV === "production") {
console.log("Production mode");
} else {
console.log("Development mode");
}
在代码到达 JavaScript 引擎之前,Bun 将 process.env.NODE_ENV
替换为 "production"
。
if ("production" === "production") {
console.log("Production mode");
} else {
console.log("Development mode");
}
它不止于此。Bun 的优化转译器足够智能,可以进行一些基本的常量折叠。
由于 "production" === "production"
始终为 true
,Bun 会将整个表达式替换为 true
值。
if (true) {
console.log("Production mode");
} else {
console.log("Development mode");
}
最后,Bun 检测到 else
分支不可达,并将其消除。
console.log("Production mode");
支持哪些类型的值?
值可以是字符串、标识符、属性或 JSON。
替换全局标识符
要使 window
的所有用法都变为 undefined
,可以使用以下命令。
bun --define window="undefined" src/index.ts
当进行服务器端渲染 (SSR) 或当您想确保代码不依赖于 window
对象时,这可能很有用。
if (typeof window !== "undefined") {
console.log("Client-side code");
} else {
console.log("Server-side code");
}
您还可以将值设置为另一个标识符。例如,要使 global
的所有用法都变为 globalThis
,可以使用以下命令。
bun --define global="globalThis" src/index.ts
global
是 Node.js 中的全局对象,但在 Web 浏览器中不是。因此,您可以使用此方法修复代码假定 global
可用的一些情况。
用 JSON 替换值
--define
也可以用于用 JSON 对象和数组替换值。
要将 AWS
的所有用法替换为 JSON 对象 {"ACCESS_KEY":"abc","SECRET_KEY":"def"}
,可以使用以下命令。
# JSON
bun --define AWS='{"ACCESS_KEY":"abc","SECRET_KEY":"def"}' src/index.ts
这些将转换为等效的 JavaScript 代码。
从
console.log(AWS.ACCESS_KEY); // => "abc"
到
console.log("abc");
用其他属性替换值
您还可以将属性传递给 --define
标志。
例如,要将 console.write
的所有用法替换为 console.log
,可以使用以下命令(需要 Bun v1.1.5 或更高版本)
bun --define console.write=console.log src/index.ts
这将转换以下输入
console.write("Hello, world!");
转换为以下输出
console.log("Hello, world!");
这与设置变量有何不同?
您还可以在代码中将 process.env.NODE_ENV
设置为 "production"
,但这无助于死代码消除。在 JavaScript 中,属性访问可能会产生副作用。Getter 和 Setter 可以是函数,甚至可以动态定义(由于原型链和 Proxy)。即使您将 process.env.NODE_ENV
设置为 "production"
,在下一行,静态分析工具也不能安全地假定 process.env.NODE_ENV
是 "production"
。
这与查找和替换或字符串替换有何不同?
--define
标志在 AST(抽象语法树)级别上运行,而不是在文本级别上运行。它发生在转译过程中,这意味着它可以用于死代码消除等优化。
字符串替换工具往往存在转义问题并替换代码中不需要的部分。