Skip to main content
--define 标志允许你声明静态可分析的常量和全局变量。它会将 JavaScript 或 TypeScript 文件中所有对某个标识符或属性的使用替换为一个常量值。此功能在运行时和 bun build 中均受到支持。这有点类似于 C/C++ 中的 #define,只是针对 JavaScript 实现的。
terminal
bun --define process.env.NODE_ENV="'production'" src/index.ts # 运行时
bun build --define process.env.NODE_ENV="'production'" src/index.ts # 构建时

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("客户端代码");
} else {
  console.log("服务器端代码");
}
你也可以将值设置为另一个标识符。例如,要将所有对 global 的使用替换成 globalThis,可以使用以下命令。
bun --define global="globalThis" src/index.ts
global 是 Node.js 中的全局对象,但在浏览器中不是。因此,你可以用这个方法修正代码中假设 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 --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(抽象语法树)级别进行操作,而不是文本级别。它发生在转译过程中,意味着它可以用于诸如死代码消除之类的优化。 字符串替换工具往往有转义问题,并且可能替换到代码中不应替换的部分。