В режиме сборки JavaScript-кода в формат IIFE (Immediately Invoked Function Expression) весь модульный код объединяется в одну самовызывающуюся функцию. Такой формат используется для запуска скриптов напрямую в браузере без систем модулей, при этом экспортируемые значения становятся свойствами одного глобального объекта.
При использовании esbuild с форматом iife возникает
ключевая проблема: как именно назвать глобальную переменную, в которую
будут помещены экспортируемые значения. Для этого применяется опция
globalName.
При сборке в формате IIFE esbuild оборачивает весь код в конструкцию вида:
(function () {
// скомпилированный код модуля
})();
Однако экспортированные значения должны быть доступны снаружи. Без дополнительной настройки esbuild не знает, как назвать объект, который будет содержать эти экспорты.
Опция globalName задаёт имя этого объекта в глобальной
области видимости.
import * as esbuild from 'esbuild';
esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
format: 'iife',
globalName: 'MyLibrary',
outfile: 'dist/bundle.js'
});
После сборки результат будет выглядеть концептуально следующим образом:
var MyLibrary = (function () {
function hello() {
return "Hello";
}
return {
hello: hello
};
})();
Теперь все экспортированные сущности доступны через
MyLibrary.
Если в исходном коде используются экспортируемые значения:
export function sum(a, b) {
return a + b;
}
export const version = "1.0.0";
После сборки с globalName: "Calc":
var Calc = (() => {
function sum(a, b) {
return a + b;
}
const version = "1.0.0";
return {
sum,
version
};
})();
Таким образом, globalName становится контейнером для
всех экспортов.
Использование globalName не только определяет имя
экспортируемого объекта, но и влияет на способ интеграции библиотеки в
глобальную среду:
Поэтому выбор имени требует строгого контроля уникальности.
При экспорте пространства имён:
export const math = {
add(a, b) {
return a + b;
}
};
Результирующая структура:
var Utils = (() => {
const math = {
add(a, b) {
return a + b;
}
};
return { math };
})();
Доступ:
Utils.math.add(2, 3);
esbuild оптимизирует структуру IIFE, но при этом соблюдает следующие принципы:
Если формат установлен в iife, но
globalName не указан, esbuild не может корректно
сформировать глобальный интерфейс для экспортов. В зависимости от
структуры кода это приводит к:
При использовании нескольких входных файлов:
esbuild.build({
entryPoints: ['a.js', 'b.js'],
bundle: true,
format: 'iife',
globalName: 'App',
outfile: 'dist/app.js'
});
esbuild объединяет все экспорты в один объект:
var App = (() => {
// код a.js
// код b.js
return {
// объединённые экспорты
};
})();
Конфликты имён разрешаются на этапе сборки через внутреннюю систему нейминга esbuild.
При подключении скомпилированного файла в браузере:
<script src="bundle.js"></script>
<script>
App.run();
</script>
globalName становится единственной точкой доступа к
функциональности библиотеки без использования модулей ES.
Использование globalName в IIFE-формате накладывает
архитектурные ограничения:
Несмотря на это, формат остаётся востребованным для встраиваемых библиотек и legacy-среды.
Опция globalName часто используется совместно с:
minify — уменьшение размера итогового кодаsourcemap — генерация карт исходного кодаtarget — контроль совместимости с браузерамиdefine — подстановка констант на этапе сборкиПример комплексной конфигурации:
esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
format: 'iife',
globalName: 'Core',
minify: true,
sourcemap: true,
target: ['es2017'],
outfile: 'dist/core.js'
});
Имя, указанное в globalName, должно соответствовать
следующим требованиям:
Нарушение этих правил приводит к конфликтам на уровне глобального scope.
Механизм работы можно описать следующим образом:
globalNameЭта модель обеспечивает предсказуемую структуру итогового бандла при минимальных накладных расходах.