Налаштування бандлера Rollup для веб-проекту
Rollup займає специфічну нішу серед бандлерів: він оптимальний там, де результат — переиспользуемая бібліотека, а не програма. NPM-пакети, design system, SDK, утиліти — саме тут Rollup переважає Webpack і Vite за рахунок якості tree-shaking та підтримки декількох форматів виведення з однієї конфіги.
Коли вибирати Rollup
Rollup не універсальний інструмент. Для SPA з hot reload та dev-сервером зручніше Vite (який сам використовує Rollup всередині для production-побудови). Вибирайте Rollup, коли вам потрібно:
- зібрати бібліотеку в форматах ESM + CJS + UMD одночасно
- отримати максимально чистий output без зайвих обгорток
- контролювати, які залежності включаються в bundle, а які залишаються
external - генерувати TypeScript-декларації поряд із скомпільованими файлами
Встановлення та базова конфіга
npm install --save-dev rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript rollup-plugin-dts
rollup.config.ts для типової TypeScript-бібліотеки:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import dts from 'rollup-plugin-dts';
import { defineConfig } from 'rollup';
import pkg from './package.json' assert { type: 'json' };
export default defineConfig([
// Основна побудова: ESM + CJS
{
input: 'src/index.ts',
external: Object.keys(pkg.peerDependencies ?? {}),
plugins: [
resolve({ extensions: ['.ts', '.tsx'] }),
commonjs(),
typescript({ tsconfig: './tsconfig.build.json' }),
],
output: [
{
file: pkg.module, // dist/index.esm.js
format: 'esm',
sourcemap: true,
},
{
file: pkg.main, // dist/index.cjs.js
format: 'cjs',
sourcemap: true,
exports: 'named',
},
],
},
// TypeScript-декларації
{
input: 'dist/types/index.d.ts',
output: { file: 'dist/index.d.ts', format: 'esm' },
plugins: [dts()],
},
]);
package.json: exports map
Сучасний package.json для бібліотеки з правильним exports:
{
"name": "my-lib",
"version": "1.0.0",
"type": "module",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js",
"types": "./dist/index.d.ts"
}
},
"files": ["dist"]
}
Зовнішні залежності та peer deps
Частова помилка — включати React або lodash в bundle бібліотеки. external повинна перераховувати всі peer-залежності:
// Автоматично з package.json
const external = [
...Object.keys(pkg.peerDependencies ?? {}),
...Object.keys(pkg.dependencies ?? {}),
];
Якщо потрібна часткова екстернализація (наприклад, включити тільки lodash/merge, але не весь lodash):
external: (id) => id.startsWith('react') || /^lodash/.test(id),
Робота з CSS та активами
Для бібліотек з CSS-модулями:
npm install --save-dev rollup-plugin-postcss
import postcss from 'rollup-plugin-postcss';
plugins: [
postcss({
modules: true,
extract: 'dist/styles.css', // окремий файл замість inject
minimize: true,
}),
]
Активи (SVG, зображення):
import url from '@rollup/plugin-url';
plugins: [
url({
include: ['**/*.svg'],
limit: 8192, // inline base64 до 8KB, інакше копіює файл
destDir: 'dist/assets',
}),
]
Багатовходова побудова
Для design system, де кожний компонент імпортується окремо (import Button from 'ui/Button'):
import { glob } from 'glob';
const entries = Object.fromEntries(
(await glob('src/components/**/*.tsx')).map((file) => [
file.replace('src/', '').replace(/\.tsx$/, ''),
file,
])
);
export default defineConfig({
input: entries,
output: {
dir: 'dist',
format: 'esm',
preserveModules: true,
preserveModulesRoot: 'src',
},
// ...
});
preserveModules: true не об'єднує все в один файл, а зберігає структуру директорій — це дозволяє tree-shaking на стороні споживача працювати на рівні файлів.
Аналіз розміру bundle
npm install --save-dev rollup-plugin-visualizer
import { visualizer } from 'rollup-plugin-visualizer';
plugins: [
visualizer({
filename: 'dist/stats.html',
gzipSize: true,
brotliSize: true,
}),
]
Після побудови відкрийте dist/stats.html — інтерактивне дерево залежностей із реальними розмірами після gzip.
Watch-режим та розробка
rollup -c --watch
Або через конфіга для більш тонкого контролю:
watch: {
include: 'src/**',
exclude: 'node_modules/**',
clearScreen: false,
},
Для розробки бібліотеки паралельно з програмою-споживачем — npm link або file: залежність в package.json споживача. У монорепозиторіїм — workspace-посилання.
Терміни
Базова настройка Rollup для TypeScript-бібліотеки (один вхід, ESM+CJS, декларації): 2–4 години. Складна настройка з CSS-модулями, багатовходовою побудовою, настройкою CI для автоматичного релізу в npm: 1–2 дні.







