Bun

指南运行时

使用 Bun 定义和替换静态全局变量和常量

--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 对象和数组替换值。

要使用 JSON 对象 {"ACCESS_KEY":"abc","SECRET_KEY":"def"} 替换 AWS 的所有用法,可以使用以下命令。

# 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.log 替换 console.write 的所有用法,可以使用以下命令(需要 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(抽象语法树)级别上操作,而不是在文本级别上操作。它发生在转换过程中,这意味着它可以用于死代码消除等优化中。

字符串替换工具往往会遇到转义问题,并替换代码中意外的部分。