定義並替換靜態全域性變數和常量
--define 標誌用於宣告可靜態分析的常量和全域性變數。它會將 JavaScript 或 TypeScript 檔案中識別符號或屬性的所有用法替換為常量值,並且在執行環境和 bun build 中均可使用。它類似於 C/C++ 中的 #define,但適用於 JavaScript。
bun --define process.env.NODE_ENV="'production'" src/index.ts # 執行環境
bun build --define process.env.NODE_ENV="'production'" src/index.ts # 建置時
Bun 會利用這些靜態已知值來消除無效程式碼並執行其他最佳化。
if (process.env.NODE_ENV === "production") {
console.log("生產模式");
} else {
console.log("開發模式");
}
在程式碼到達 JavaScript 引擎之前,Bun 會將 process.env.NODE_ENV 替換為 "production"。
if ("production" === "production") { // [!code ++]
console.log("生產模式");
} else {
console.log("開發模式");
}
Bun 的最佳化型轉譯器也會執行基本的常量摺疊。
由於 "production" === "production" 始終為 true,Bun 會將整個表示式替換為 true 值,並移除不可達的 else 分支。
if (true) { // [!code ++]
console.log("生產模式");
}
若還要將周圍的 if 框架摺疊為以下輸出,請傳入 --minify-syntax(--minify 也會啟用該選項):
bun build --define process.env.NODE_ENV="'production'" --minify-syntax src/index.ts
console.log("生產模式");
支援哪些型別的值?
值可以是字串、識別符號、屬性或 JSON。
替換全域性識別符號
將所有 window 的使用替換為 undefined:
bun --define window="undefined" src/index.ts
此替換適用於伺服器端渲染(SSR),或確保程式碼不相依 window 物件。
if (typeof window !== "undefined") {
console.log("客戶端程式碼");
} else {
console.log("伺服器端程式碼");
}
該值也可以是另一個識別符號。例如,將所有 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
Bun 會將這些內容轉換為等效的 JavaScript 程式碼。
從:
console.log(AWS.ACCESS_KEY); // => "abc"
變成:
console.log({ ACCESS_KEY: "abc", SECRET_KEY: "def" }.ACCESS_KEY);
使用其他屬性替換值
你也可以傳遞屬性給 --define 標誌。
例如,將所有 console.write 的使用替換為 console.log:
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",靜態分析工具也無法假定它在下一行仍然是 "production"。
這和查詢替換或字串替換有什麼不同?
--define 標誌操作的是 AST(抽象語法樹),而不是文本。替換髮生在轉譯過程中,因此可以參與死程式碼消除等最佳化。
字串替換工具往往有轉義問題,並且可能替換到程式碼中不應替換的部分。