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(抽象語法樹)層級上運作,而不是在文字層級上運作。它發生在轉譯過程中,這表示它可以用於死程式碼消除等最佳化中。

字串取代工具往往會有跳脫字元問題,並取代程式碼中意外的部分。