--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(抽象語法樹)層級上運作,而不是在文字層級上運作。它發生在轉譯過程中,這表示它可以用於死程式碼消除等最佳化中。
字串取代工具往往會有跳脫字元問題,並取代程式碼中意外的部分。