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 物件和陣列替換值。

要將 `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(抽象語法樹)級別執行,而不是在文字級別。它發生在轉譯過程中,這意味著它可以用於死程式碼消除等最佳化。

字串替換工具往往存在轉義問題,並會替換程式碼中不相關的部分。