ES-модули (ECMAScript Modules, ESM) представляют собой стандартную
систему модулей JavaScript, основанную на статическом анализе
зависимостей через конструкции import и
export. В контексте Rollup этот формат является основным и
наиболее «нативным» целевым результатом сборки, поскольку архитектура
бандлера изначально оптимизирована под работу со статическим графом
импортов.
При указании формата вывода es Rollup генерирует код,
который сохраняет модульную структуру приложения или библиотеки,
минимально трансформируя исходные import и
export:
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
Результат такой сборки сохраняет ESM-синтаксис:
// dist/bundle.js
export { something } from './module.js';
import { helper } from './helper.js';
function main() {
return helper();
}
export { main };
В отличие от форматов iife или cjs, здесь
отсутствует оборачивание в функцию или CommonJS-объекты. Это позволяет
использовать итоговый файл напрямую в современных браузерах и в Node.js
при включённой поддержке ESM.
Ключевая особенность ES-модулей заключается в их статической природе. Rollup использует это для построения полного графа зависимостей на этапе сборки. Это означает, что:
Пример влияния статического анализа:
// util.js
export function used() {
return 'used';
}
export function unused() {
return 'unused';
}
// index.js
import { used } from './util.js';
console.log(used());
Rollup при format: "es" исключит unused,
поскольку она не входит в граф использования.
ES-модули являются основой tree-shaking в Rollup. Так как экспортируемые сущности определяются статически, Rollup может безопасно удалять неиспользуемые части кода.
Важный аспект заключается в том, что эффективность tree-shaking зависит не только от Rollup, но и от структуры самого кода:
export const a = 1;
export const b = 2;
export const c = 3;
Если используется только a, остальные экспорты
исключаются при корректной конфигурации.
Однако tree-shaking может быть нарушен побочными эффектами:
export function init() {
console.log('side effect');
}
Если функция вызывается в модуле верхнего уровня или считается имеющей побочные эффекты, Rollup может сохранить её даже без явного использования.
Для оптимальной работы ES-формата важную роль играет поле
sideEffects в package.json:
{
"sideEffects": false
}
Это позволяет Rollup и другим инструментам (например, Webpack) безопасно удалять неиспользуемые модули целиком.
Если указано:
{
"sideEffects": ["*.css"]
}
то CSS-файлы сохраняются, а JS-модули продолжают оптимизироваться.
При использовании ES-формата часто применяется опция
preserveModules, которая сохраняет исходную структуру
файлов:
export default {
input: 'src/index.js',
output: {
dir: 'dist',
format: 'es',
preserveModules: true
}
};
Результат:
dist/
index.js
utils/
helper.js
Каждый исходный модуль становится отдельным файлом. Это особенно важно для библиотек, которые:
import { x } from 'lib/utils');При сравнении ES-модулей и CommonJS в Rollup выявляются фундаментальные различия:
| Характеристика | ES modules (es) |
CommonJS (cjs) |
|---|---|---|
| Анализ зависимостей | статический | динамический |
| Tree-shaking | полноценный | ограниченный |
| Поддержка браузеров | нативная | отсутствует |
| Экспорт | named/default | module.exports |
| Оптимизация | высокая | средняя |
Rollup при format: "es" избегает преобразования модулей
в CommonJS-обёртки, что снижает накладные расходы и сохраняет
прозрачность зависимостей.
ES-модули поддерживают динамический импорт через
import():
export async function loadModule() {
const module = await import('./heavy.js');
return module.run();
}
Rollup использует эту конструкцию для автоматического code splitting
при format: "es":
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
chunkFileNames: 'chunks/[name]-[hash].js'
}
};
Результатом становится разделение кода на чанки:
dist/
main.js
chunks/
heavy-abc123.js
ES-модули в формате Rollup полностью совместимы с современными окружениями.
В браузере:
<script type="module" src="/dist/main.js"></script>
В Node.js (при "type": "module"):
{
"type": "module"
}
И импорт:
import { main } from './dist/main.js';
Важно учитывать расширения файлов: в Node.js ESM требуется явное
указание .js.
При сборке в ES-формате часто требуется исключение внешних библиотек:
export default {
input: 'src/index.js',
output: {
file: 'dist/index.js',
format: 'es'
},
external: ['react', 'lodash']
};
Это приводит к сохранению импортов:
import React from 'react';
import { debounce } from 'lodash';
Rollup не включает эти зависимости в бандл, сохраняя ES-синтаксис.
При работе с библиотеками, использующими CommonJS, Rollup выполняет
преобразование через плагины (например,
@rollup/plugin-commonjs). В ES-выводе это может приводить к
дополнительным обёрткам:
import pkg from 'cjs-lib';
const { method } = pkg;
Важно учитывать, что такие преобразования могут частично снижать преимущества чистого ES-формата.
Для максимальной эффективности ES-вывода применяются следующие практики:
require;export * в
критичных участках.Пример оптимальной структуры:
// math/add.js
export function add(a, b) {
return a + b;
}
// math/multiply.js
export function multiply(a, b) {
return a * b;
}
// index.js
export { add } from './math/add.js';
export { multiply } from './math/multiply.js';
Rollup при ES-выводе стремится сохранить читаемость и модульность, а не минимизировать количество файлов любой ценой. В отличие от UMD или IIFE форматов, здесь приоритетом является:
Типичный итоговый бандл остаётся максимально близким к исходному коду, но с разрешёнными зависимостями и удалённым неиспользуемым кодом.
ES-формат не предполагает минификацию как часть своей модели. Однако
он часто используется вместе с @rollup/plugin-terser:
import terser from '@rollup/plugin-terser';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'es'
},
plugins: [terser()]
};
Минификация в этом случае не меняет модульную структуру, а только упрощает синтаксис:
export function a(n,o){return n+o}
Несмотря на универсальность, ES-вывод имеет ограничения:
Эти ограничения компенсируются за счёт современных окружений и инструментов транспиляции (Babel, TypeScript).
ES-формат стал стандартом для публикации библиотек, ориентированных на tree-shaking. Rollup использует его как основной режим для:
Типичная конфигурация библиотеки:
export default {
input: 'src/index.js',
output: [
{
file: 'dist/index.esm.js',
format: 'es'
},
{
file: 'dist/index.cjs.js',
format: 'cjs'
}
]
};
ES-версия при этом остаётся основной точкой оптимизации.
ES-модули в Rollup формируют промежуточный слой между исходным кодом и конечным окружением исполнения. Они обеспечивают: