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 中的全域物件,但在網頁瀏覽器中則不是。因此,您可以使用它來修正某些程式碼假設 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 (抽象語法樹) 層級運作,而不是在文字層級。它發生在轉譯過程中,這表示它可以用於死碼消除等最佳化。

字串取代工具往往會出現跳脫問題,並取代程式碼中不希望取代的部分。