Флаг --define позволяет объявлять статически анализируемые константы и глобальные переменные. Он заменяет все использования идентификатора или свойства в JavaScript или TypeScript файле на константное значение. Эта функция поддерживается во время выполнения, а также в bun build. Это похоже на #define в C/C++, но для 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") {
console.log("Режим продакшена");
} else {
console.log("Режим разработки");
}На этом всё не заканчивается. Оптимизирующий транспилятор Bun достаточно умен, чтобы выполнять некоторую базовую свёртку констант.
Поскольку "production" === "production" всегда true, Bun заменяет всё выражение на значение true.
if (true) {
console.log("Режим продакшена");
} else {
console.log("Режим разработки");
}И наконец, Bun обнаруживает, что ветка else недостижима, и удаляет её.
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.tsglobal — это глобальный объект в 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 --define console.write=console.log src/index.tsЭто преобразует следующий входной код:
console.write("Hello, world!");В следующий выходной код:
console.log("Hello, world!");Чем это отличается от установки переменной?
Вы также можете установить process.env.NODE_ENV в "production" в вашем коде, но это не поможет с удалением мёртвого кода. В JavaScript доступ к свойствам может иметь побочные эффекты. Геттеры и сеттеры могут быть функциями и даже динамически определены (из-за цепочек прототипов и Proxy). Даже если вы установите process.env.NODE_ENV в "production", в следующей строке не будет безопасно для инструментов статического анализа предполагать, что process.env.NODE_ENV равен "production".
Чем это отличается от поиска и замены или замены строк?
Флаг --define работает на уровне AST (абстрактного синтаксического дерева), а не на текстовом уровне. Это происходит во время транспиляции, что означает, что его можно использовать в оптимизациях, таких как удаление мёртвого кода.
Инструменты замены строк часто имеют проблемы с экранированием и заменяют непреднамеренные части кода.