Встраивание полифилов в сборку Rollup является ключевым этапом при подготовке JavaScript-библиотек и приложений к выполнению в средах с различным уровнем поддержки стандартов ECMAScript и Node.js API. Основная задача полифилов заключается в эмуляции отсутствующих возможностей среды исполнения без изменения исходного кода, при этом Rollup, как ES-модульный бандлер с агрессивной оптимизацией, требует особого подхода к их подключению.
Rollup ориентирован на статический анализ модулей и удаление неиспользуемого кода (tree-shaking). Это напрямую влияет на стратегию подключения полифилов:
require не анализируются корректно без
дополнительных плагинов;Полифилы в Rollup могут быть подключены на нескольких уровнях: входная точка, плагины трансформации, либо через автоматическую подстановку зависимостей при сборке.
Наиболее прозрачный подход заключается в явном подключении необходимых полифилов в entry-файле:
import 'core-js/actual/array/from';
import 'core-js/actual/promise';
import 'regenerator-runtime/runtime';
Данная стратегия обеспечивает полный контроль над набором полифилов и их версионированием. При этом Rollup способен учитывать такие импорты при tree-shaking, если полифилы реализованы как ESM.
Современные версии core-js предоставляют модульный
импорт:
core-js/es/... — полные полифилы;core-js/actual/... — актуальные реализации;core-js/stable/... — стабильные API.Такой подход минимизирует размер бандла, так как подключаются только используемые части.
При сборке библиотек для браузера часто требуется эмуляция Node.js модулей:
pathbufferstreamcryptoprocessДля этого используется плагин:
@rollup/plugin-polyfill-node
Он предоставляет ESM-совместимые реализации Node.js стандартной библиотеки.
Конфигурация:
import nodePolyfills from '@rollup/plugin-polyfill-node';
export default {
input: 'src/index.js',
output: {
format: 'esm',
dir: 'dist'
},
plugins: [
nodePolyfills()
]
};
Особенность данного подхода заключается в том, что Rollup не пытается самостоятельно интерпретировать Node.js API, а полностью делегирует это плагину.
Некоторые библиотеки ожидают наличие глобальных переменных:
processBufferglobalДля их внедрения используется @rollup/plugin-inject:
import inject from '@rollup/plugin-inject';
export default {
plugins: [
inject({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
})
]
};
Этот механизм подменяет идентификаторы на соответствующие импорты, не изменяя исходный код модулей.
Многие полифилы поставляются в формате CommonJS. Для корректной интеграции требуется:
@rollup/plugin-commonjs
@rollup/plugin-node-resolve
Конфигурация:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export default {
plugins: [
resolve({
browser: true,
preferBuiltins: false
}),
commonjs()
]
};
Ключевой момент заключается в том, что без commonjs
многие полифилы не будут корректно интерпретированы Rollup.
Дублирование возникает в нескольких случаях:
core-js;Для контроля используются следующие техники:
Создание отдельного модуля:
// polyfills.js
import 'core-js/stable';
import 'regenerator-runtime/runtime';
И импорт его только один раз в entry.
В package.json:
{
"sideEffects": [
"polyfills.js"
]
}
Это предотвращает удаление полифилов tree-shaking-ом.
Babel часто используется совместно с Rollup для автоматической
подстановки полифилов через @babel/preset-env и
useBuiltIns.
Режимы:
usage — импортирует только используемые полифилы;entry — требует явного подключения core-js в
entry;false — отключает автоматические полифилы.Конфигурация:
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
corejs: 3
}]
]
Важно учитывать, что Babel может конфликтовать с ручной стратегией подключения полифилов в Rollup, приводя к дублированию кода.
Rollup удаляет неиспользуемые экспорты, но полифилы часто работают через side effects:
Для сохранения таких модификаций необходимо учитывать:
export default {
treeshake: {
moduleSideEffects: true
}
};
Или точечная настройка для отдельных модулей.
При универсальных библиотеках часто применяется dual build:
Пример условной конфигурации:
const isBrowser = process.env.BUILD === 'browser';
export default {
plugins: [
isBrowser && nodePolyfills()
].filter(Boolean)
};
Такой подход предотвращает избыточное увеличение размера серверной сборки.
Наиболее часто подключаемые возможности:
PromiseSymbolArray.fromObject.assignString.prototype.includesВ современных проектах они импортируются точечно:
import 'core-js/features/promise';
import 'core-js/features/array/from';
Такой подход позволяет минимизировать итоговый бандл и избежать загрузки ненужных полифилов.
Асинхронные функции и генераторы требуют:
import 'regenerator-runtime/runtime';
При использовании Babel с
@babel/plugin-transform-runtime возможно исключение
дублирования runtime-кода.
commonjs плагина
Rollup;node-resolve, приводящее к пропущенным
зависимостям;useBuiltIns: usage и
ручных импортов;Каждая из этих ошибок приводит либо к увеличению бандла, либо к некорректному поведению в рантайме.
Основные методы уменьшения размера:
core-js;Эффективная стратегия всегда строится вокруг минимального набора полифилов, строго соответствующего целевой среде исполнения.