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