В Webpack DefinePlugin используется для статической
подстановки значений в исходный код во время сборки. Плагин выполняет
текстовую замену идентификаторов на заданные выражения, что позволяет
внедрять конфигурационные константы, переключать окружения, убирать
лишний код и управлять поведением приложения без изменения
исходников.
Механизм работает на уровне компиляции: значения подставляются до
выполнения кода в браузере или Node.js. Это делает
DefinePlugin инструментом, тесно связанным с оптимизацией и
tree-shaking.
Плагин не создает переменные в рантайме. Он заменяет идентификаторы в коде на этапе сборки с помощью AST-преобразований.
Пример:
new webpack.DefinePlugin({
API_URL: '"https://api.example.com"'
});
Исходный код:
fetch(API_URL + "/users");
После сборки:
fetch("https://api.example.com" + "/users");
Ключевой момент заключается в том, что подстановка происходит синтаксически, поэтому важно корректно задавать значения (например, строки должны быть экранированы).
Плагин не добавляет кавычки автоматически. Поэтому строковые значения требуют явного сериализованного вида.
Правильный вариант:
new webpack.DefinePlugin({
APP_NAME: JSON.stringify("MyApp")
});
Результат:
const name = "MyApp";
Неправильный вариант:
APP_NAME: "MyApp"
В этом случае результатом будет некорректный Jav * aScript:
const name = MyApp;
DefinePlugin поддерживает не только строки и числа, но и сложные структуры, если они сериализованы:
new webpack.DefinePlugin({
CONFIG: JSON.stringify({
api: "https://api.example.com",
retry: 3,
features: {
auth: true,
payments: false
}
})
});
После сборки:
const CONFIG = {"api":"https://api.example.com","retry":3,"features":{"auth":true,"payments":false}};
Такой подход часто используется для конфигураций фронтенда, но требует осторожности: итоговый объект становится частью бандла и не может изменяться динамически.
Одно из главных применений — управление условными блоками, которые могут быть удалены оптимизатором.
new webpack.DefinePlugin({
__DEV__: JSON.stringify(true)
});
Использование:
if (__DEV__) {
console.log("Debug mode");
}
После минификации и tree-shaking:
console.log("Debug mode");
или полностью удаляется:
// блок исчезает
Если значение статически известно, UglifyJS/Terser может удалить мертвый код.
Частый паттерн — внедрение режима сборки:
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
});
или явно:
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("production")
});
Использование:
if (process.env.NODE_ENV === "production") {
enableAnalytics();
}
Это позволяет библиотекам (React, Vue и др.) включать оптимизированные ветки кода.
Webpack не предоставляет process.env в браузере
автоматически. DefinePlugin используется для эмуляции
переменных окружения:
new webpack.DefinePlugin({
"process.env.API_URL": JSON.stringify("https://api.example.com"),
"process.env.DEBUG": JSON.stringify(false)
});
Использование:
fetch(process.env.API_URL + "/users");
После сборки:
fetch("https://api.example.com" + "/users");
Важно понимать, что process.env здесь не объект, а набор
строковых замен на уровне AST.
DefinePlugin поддерживает вложенные ключи через строковые пути:
new webpack.DefinePlugin({
"APP.VERSION": JSON.stringify("1.0.0"),
"APP.MODE": JSON.stringify("stable")
});
Использование:
console.log(APP.VERSION);
Результат:
console.log("1.0.0");
При этом APP не создается как объект — это просто
текстовая замена.
DefinePlugin и EnvironmentPlugin часто
используются вместе, но имеют разную семантику.
EnvironmentPlugin:
process.envПример:
new webpack.EnvironmentPlugin(["NODE_ENV", "API_URL"]);
DefinePlugin:
DefinePlugin может подставлять не только литералы, но и выражения:
new webpack.DefinePlugin({
BUILD_TIME: JSON.stringify(Date.now())
});
или:
new webpack.DefinePlugin({
VERSION: JSON.stringify(require("./package.json").version)
});
Однако важно учитывать, что выражения вычисляются во время запуска Webpack, а не в браузере.
DefinePlugin работает как препроцессор. Он не понимает семантику JavaScript полностью, поэтому возможны неожиданные эффекты:
const obj = {
API_URL
};
будет преобразовано в:
const obj = {
"https://api.example.com"
};
что может изменить структуру кода.
Все значения фиксируются на этапе сборки. Изменить их после загрузки бандла невозможно.
Большие JSON-конфигурации увеличивают размер итогового файла, поскольку становятся частью кода.
Типичная ошибка:
new webpack.DefinePlugin({
API: "https://example.com"
});
Результат — некорректный JavaScript. Поэтому почти всегда требуется сериализация.
DefinePlugin тесно связан с Terser. Когда значения известны на этапе сборки, возможно удаление веток:
if (false) {
doSomething();
}
или:
if (__FEATURE_X__) {
featureX();
}
При false блок исчезает полностью, что уменьшает размер
бандла и улучшает производительность.
DefinePlugin часто применяется в следующих сценариях:
Пример комплексной конфигурации:
new webpack.DefinePlugin({
__DEV__: JSON.stringify(false),
__TEST__: JSON.stringify(false),
"process.env.NODE_ENV": JSON.stringify("production"),
"process.env.API_URL": JSON.stringify("https://api.example.com"),
"FEATURE_FLAGS": JSON.stringify({
chat: true,
payments: false
})
});
При использовании TypeScript необходимо объявлять глобальные переменные:
declare const __DEV__: boolean;
declare const API_URL: string;
Без этого компилятор будет выдавать ошибки о несуществующих идентификаторах.
DefinePlugin особенно эффективен вместе с:
Комбинация позволяет:
DefinePlugin фактически реализует концепцию compile-time constants, где конфигурация становится частью исходного кода после сборки.
Это приближает JavaScript-сборку к поведению языков с препроцессором, но с более глубокой интеграцией в AST Webpack и систему оптимизации.