執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

定義並替換靜態全域性變數和常量

--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 會利用這些靜態已知值來消除無效程式碼並執行其他最佳化。

TypeScript
if (process.env.NODE_ENV === "production") {
  console.log("生產模式");
} else {
  console.log("開發模式");
}

在程式碼到達 JavaScript 引擎之前,Bun 會將 process.env.NODE_ENV 替換為 "production"。

TypeScript
if ("production" === "production") { // [!code ++]
  console.log("生產模式");
} else {
  console.log("開發模式");
}

Bun 的最佳化型轉譯器也會執行基本的常量摺疊。

由於 "production" === "production" 始終為 true,Bun 會將整個表示式替換為 true 值,並移除不可達的 else 分支。

TypeScript
if (true) { // [!code ++]
  console.log("生產模式");
}

若還要將周圍的 if 框架摺疊為以下輸出,請傳入 --minify-syntax(--minify 也會啟用該選項):

terminal
bun build --define process.env.NODE_ENV="'production'" --minify-syntax src/index.ts
TypeScript
console.log("生產模式");

支援哪些型別的值?

值可以是字串、識別符號、屬性或 JSON。

替換全域性識別符號

將所有 window 的使用替換為 undefined:

shell
bun --define window="undefined" src/index.ts

此替換適用於伺服器端渲染(SSR),或確保程式碼不相依 window 物件。

JavaScript
if (typeof window !== "undefined") {
  console.log("客戶端程式碼");
} else {
  console.log("伺服器端程式碼");
}

該值也可以是另一個識別符號。例如,將所有 global 的使用替換為 globalThis:

shell
bun --define global="globalThis" src/index.ts

global 是 Node.js 中的全域性物件,但在 Web 瀏覽器中並不是,因此此替換可以修復假設 global 可用的程式碼。

使用 JSON 替換值

--define 也可以將值替換為 JSON 物件和陣列。

將所有 AWS 的使用替換為 JSON 物件 {"ACCESS_KEY":"abc","SECRET_KEY":"def"}:

shell
# JSON
bun --define AWS='{"ACCESS_KEY":"abc","SECRET_KEY":"def"}' src/index.ts

Bun 會將這些內容轉換為等效的 JavaScript 程式碼。

從:

TypeScript
console.log(AWS.ACCESS_KEY); // => "abc"

變成:

TypeScript
console.log({ ACCESS_KEY: "abc", SECRET_KEY: "def" }.ACCESS_KEY);

使用其他屬性替換值

你也可以傳遞屬性給 --define 標誌。

例如,將所有 console.write 的使用替換為 console.log:

shell
bun --define console.write=console.log src/index.ts

這會將以下輸入轉換:

TypeScript
console.write("Hello, world!");

變成以下輸出:

TypeScript
console.log("Hello, world!");

這和設定變數有什麼不同?

你也可以在程式碼中將 process.env.NODE_ENV 設定為 "production",但這對死程式碼消除沒有幫助。在 JavaScript 中,屬性訪問可能產生副作用。Getter 和 setter 可以是函式,甚至可以動態定義(由於原型鏈和 Proxy)。即使你將 process.env.NODE_ENV 設定為 "production",靜態分析工具也無法假定它在下一行仍然是 "production"。

這和查詢替換或字串替換有什麼不同?

--define 標誌操作的是 AST(抽象語法樹),而不是文本。替換髮生在轉譯過程中,因此可以參與死程式碼消除等最佳化。

字串替換工具往往有轉義問題,並且可能替換到程式碼中不應替換的部分。