A flag --define permite declarar constantes e globais estaticamente analisáveis. Ela substitui todos os usos de um identificador ou propriedade em um arquivo JavaScript ou TypeScript por um valor constante. Este recurso é suportado em tempo de execução e também em bun build. Isso é meio que similar a #define em C/C++, exceto que para JavaScript.
bun --define process.env.NODE_ENV="'production'" src/index.ts # Tempo de execução
bun build --define process.env.NODE_ENV="'production'" src/index.ts # BuildEsses valores estaticamente conhecidos são usados pelo Bun para eliminação de código morto e outras otimizações.
if (process.env.NODE_ENV === "production") {
console.log("Modo produção");
} else {
console.log("Modo desenvolvimento");
}Antes do código chegar ao motor JavaScript, o Bun substitui process.env.NODE_ENV por "production".
if ("production" === "production") {
console.log("Modo produção");
} else {
console.log("Modo desenvolvimento");
}Não para por aí. O transpilador otimizador do Bun é inteligente o suficiente para fazer alguma dobra de constante básica.
Como "production" === "production" é sempre true, o Bun substitui toda a expressão pelo valor true.
if (true) {
console.log("Modo produção");
} else {
console.log("Modo desenvolvimento");
}E finalmente, o Bun detecta que o branch else não é alcançável e o elimina.
console.log("Modo produção");Quais tipos de valores são suportados?
Valores podem ser strings, identificadores, propriedades ou JSON.
Substituir identificadores globais
Para fazer todos os usos de window serem undefined, você pode usar o seguinte comando.
bun --define window="undefined" src/index.tsIsso pode ser útil quando faz Server-Side Rendering (SSR) ou quando quer ter certeza de que o código não depende do objeto window.
if (typeof window !== "undefined") {
console.log("Código client-side");
} else {
console.log("Código server-side");
}Você também pode definir o valor como outro identificador. Por exemplo, para fazer todos os usos de global serem globalThis, você pode usar o seguinte comando.
bun --define global="globalThis" src/index.tsglobal é um objeto global no Node.js, mas não em navegadores web. Então, você pode usar isso para corrigir alguns casos onde o código assume que global está disponível.
Substituir valores com JSON
--define também pode ser usado para substituir valores por objetos e arrays JSON.
Para substituir todos os usos de AWS pelo objeto JSON {"ACCESS_KEY":"abc","SECRET_KEY":"def"}, você pode usar o seguinte comando.
# JSON
bun --define AWS='{"ACCESS_KEY":"abc","SECRET_KEY":"def"}' src/index.tsEsses serão transformados no código JavaScript equivalente.
De:
console.log(AWS.ACCESS_KEY); // => "abc"Para:
console.log("abc");Substituir valores com outras propriedades
Você também pode passar propriedades para a flag --define.
Por exemplo, para substituir todos os usos de console.write por console.log, você pode usar o seguinte comando
bun --define console.write=console.log src/index.tsIsso transforma a seguinte entrada:
console.write("Hello, world!");Na seguinte saída:
console.log("Hello, world!");Como isso é diferente de definir uma variável?
Você também pode definir process.env.NODE_ENV como "production" em seu código, mas isso não ajudá com eliminação de código morto. Em JavaScript, acessos a propriedades podem ter efeitos colaterais. Getters e setters podem ser funções e até mesmo definidos dinamicamente (devido a cadeias de protótipo e Proxy). Mesmo se você definir process.env.NODE_ENV como "production", na próxima linha, não é seguro para ferramentas de análise estática assumirem que process.env.NODE_ENV é "production".
Como isso é diferente de find-and-replace ou substituição de string?
A flag --define opera no nível AST (Abstract Syntax Tree), não no nível de texto. Ela acontece durante o processo de transpilação, o que significa que pode ser usada em otimizações como eliminação de código morto.
Ferramentas de substituição de string tendem a ter problemas de escaping e substituem partes não intencionais do código.