Rollup изначально ориентирован на работу с современным JavaScript и ESM-модулями, предполагая максимально статический анализ кода. Однако реальный промышленный код почти всегда требует транспиляции: поддержки старых браузеров, преобразования синтаксиса TypeScript/JSX, использования полифилов и трансформаций возможностей ECMAScript, которые ещё не везде реализованы.
Babel выступает промежуточным этапом трансформации кода, расширяя возможности Rollup за счёт преобразования синтаксиса до того уровня, который требуется целевой среде выполнения.
Связка Rollup и Babel строится на разделении ответственности:
Ключевая особенность заключается в том, что Babel не должен разрушать ESM-структуру до этапа анализа Rollup. Иначе теряется возможность эффективного удаления неиспользуемого кода.
Типовой порядок работы плагинов:
Основной способ подключения Babel в Rollup осуществляется через
официальный плагин @rollup/plugin-babel.
Установка зависимостей:
npm install --save-dev @rollup/plugin-babel @babel/core
Минимальная конфигурация Rollup:
import babel from '@rollup/plugin-babel';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
plugins: [
babel({
babelHelpers: 'bundled'
})
]
};
Критически важный момент — порядок плагинов. Babel должен применяться до большинства трансформаций, но после чтения исходного кода.
Типичная ошибка — преобразование модулей до анализа Rollup. Это приводит к следующим проблемам:
Правильный подход — применять Babel как трансформатор синтаксиса, сохраняя ESM-структуру максимально долго.
Babel конфиг обычно задаётся через .babelrc или
babel.config.json.
Пример базовой конфигурации:
{
"presets": [
["@babel/preset-env", {
"modules": false,
"targets": {
"browsers": "> 0.25%, not dead"
}
}]
]
}
Ключевая настройка modules: false предотвращает
преобразование ES-модулей в CommonJS. Это необходимо для корректной
работы Rollup.
@babel/preset-env управляет трансформацией синтаксиса в
зависимости от целевых окружений.
В связке с Rollup важно учитывать:
useBuiltIns при необходимостиПример более продвинутой конфигурации:
{
"presets": [
["@babel/preset-env", {
"modules": false,
"useBuiltIns": "usage",
"corejs": 3
}]
]
}
Такой подход позволяет автоматически подставлять полифилы только там, где они реально используются.
При трансформациях Babel вставляет вспомогательные функции (helpers), например для классов, async/await, spread-операторов.
Без дополнительной настройки это приводит к:
babel({
babelHelpers: 'bundled'
})
В этом режиме helpers вставляются прямо в бандл. Подходит для небольших библиотек, но увеличивает итоговый размер при множестве модулей.
Более оптимальный вариант:
babel({
babelHelpers: 'runtime',
plugins: ['@babel/plugin-transform-runtime']
})
Этот режим выносит вспомогательные функции в отдельный runtime и переиспользует их.
Дополнительная зависимость:
npm install --save-dev @babel/plugin-transform-runtime
npm install @babel/runtime
Babel может негативно влиять на tree-shaking, если:
Чтобы сохранить эффективность Rollup:
modules: falseВ package.json библиотеки важно явно указывать:
{
"sideEffects": false
}
или перечислять исключения.
Babel часто используется как альтернатива tsc или
@rollup/plugin-typescript.
Для этого добавляются пресеты:
npm install --save-dev @babel/preset-typescript @babel/preset-react
Конфигурация:
{
"presets": [
"@babel/preset-typescript",
"@babel/preset-react"
]
}
Важно учитывать, что Babel:
tsc --noEmit для проверки типовТипичный production pipeline включает несколько плагинов:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
export default {
input: 'src/index.js',
output: {
file: 'dist/index.js',
format: 'esm'
},
plugins: [
resolve(),
commonjs(),
babel({
babelHelpers: 'runtime',
exclude: 'node_modules/**'
})
]
};
Здесь важен порядок:
node-resolve — поиск модулейcommonjs — конвертация CJS зависимостейbabel — финальная трансформация синтаксисаОбычно node_modules не проходят через Babel:
babel({
exclude: 'node_modules/**'
})
Это ускоряет сборку и предотвращает конфликты с уже транспилированными библиотеками.
Однако иногда требуется обратное — транспиляция отдельных пакетов, если они поставляются в современном синтаксисе:
babel({
include: ['src/**', 'node_modules/some-modern-lib/**']
})
Babel является одним из самых дорогих этапов в Rollup pipeline.
Основные факторы замедления:
Оптимизационные подходы:
@rollup/plugin-babel с cacheDev-конфигурация может быть более мягкой:
Production-конфигурация ориентирована на размер и совместимость:
preset-env с target browsersbabelHelpers: runtimecore-jsПример разделения:
const isProd = !process.env.ROLLUP_WATCH;
export default {
plugins: [
babel({
babelHelpers: isProd ? 'runtime' : 'bundled'
})
]
};
Rollup получает максимальную выгоду, когда исходный код остаётся в формате ESM до финальной стадии. Babel, в свою очередь, должен работать как «слой синтаксической адаптации», не вмешиваясь в модульную структуру.
Нарушение этого принципа приводит к:
Правильная интеграция сохраняет преимущества обеих систем: статический анализ Rollup и универсальность Babel.
Часто встречающиеся проблемы:
modules: 'commonjs' в Babel preset-envexclude: node_modulescommonjs и babelКаждая из этих ошибок влияет либо на корректность сборки, либо на её эффективность.
В сложных проектах часто применяется частичная трансформация:
Это достигается через include и
exclude:
babel({
include: 'src/**',
exclude: ['node_modules/**', 'src/vendor/**']
})
Такой подход снижает нагрузку на сборку и делает пайплайн более предсказуемым.
Babel используется для поддержки:
Rollup сам по себе не трансформирует синтаксис, поэтому Babel становится обязательным слоем для кросс-браузерной совместимости.
Логическая цепочка сборки в связке Rollup и Babel выглядит как последовательность независимых этапов:
Эта модель позволяет сохранять баланс между современным синтаксисом разработки и требованиями целевых сред выполнения.