Rollup Cheatsheet¶
Rollup - Módulo ES de próxima generación Bundler__HTML_TAG_66_
Rollup es un paquete de módulos para JavaScript que recopila pequeñas piezas de código en algo más grande y más complejo, como una biblioteca o aplicación. Utiliza el nuevo formato estandarizado para módulos de código incluidos en la revisión ES6 de JavaScript.
Tabla de contenidos¶
- Instalación
- Configuración básica
- [Opciones de entrada] (opciones de entrada)
- [Opciones de salida] (opciones de salida)
- Plugins
- [dependencias externas] (dependencias externas)
- [Tree Shaking]
- Code Splitting
- [Modo de espera] (Modo de reloj)
- Development vs Production
- Incorporación del tipo
- CSS and Assets
- [Desarrollo de la Biblioteca] (desarrollo de la biblioteca)
- Configuración avanzada
- Optimización de la ejecución
- [Troubleshooting] (#troubleshooting)
- [Prácticas mejores] (prácticas mejores)
Instalación¶
Global installation¶
Instalación local (recomendada)¶
# Initialize npm project
npm init -y
# Install Rollup locally
npm install --save-dev rollup
# Install common plugins
npm install --save-dev @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-babel
Package.json Scripts¶
{
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"build:prod": "NODE_ENV=production rollup -c"
}
}
Configuración básica¶
Minimal rollup.config.js¶
Configuración básica completa¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
name: 'MyBundle',
sourcemap: true
},
plugins: [
resolve(),
commonjs(),
terser()
]
};
Múltiples configuraciones¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
const configs = [
// ES module build
{
input: 'src/main.js',
output: {
file: 'dist/bundle.esm.js',
format: 'es'
},
plugins: [resolve(), commonjs()]
},
// UMD build
{
input: 'src/main.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
},
plugins: [resolve(), commonjs()]
}
];
export default configs;
Configuración basada en el medio ambiente
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: !production
},
plugins: [
resolve(),
commonjs(),
production && terser()
]
};
Opciones de entrada¶
Punto de entrada único¶
Multiple Entry Points¶
Dynamic Entry Points¶
import glob from 'glob';
const entries = glob.sync('src/pages/*.js').reduce((acc, path) => {
const entry = path.replace('src/pages/', '').replace('.js', '');
acc[entry] = path;
return acc;
}, {});
export default {
input: entries
};
Entrada con dependencias externas¶
Output Options¶
Formatos de salida¶
// ES Module
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.esm.js',
format: 'es'
}
};
// CommonJS
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs'
}
};
// UMD (Universal Module Definition)
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
}
};
// IIFE (Immediately Invoked Function Expression)
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
name: 'MyApp'
}
};
// AMD (Asynchronous Module Definition)
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.amd.js',
format: 'amd'
}
};
// SystemJS
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.system.js',
format: 'system'
}
};
Multiple Output Formats¶
export default {
input: 'src/main.js',
output: [
{
file: 'dist/bundle.esm.js',
format: 'es'
},
{
file: 'dist/bundle.cjs.js',
format: 'cjs'
},
{
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
}
]
};
Output Directory¶
export default {
input: {
main: 'src/main.js',
admin: 'src/admin.js'
},
output: {
dir: 'dist',
format: 'es',
entryFileNames: '[name].js',
chunkFileNames: '[name]-[hash].js'
}
};
Mapas Fuente¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: true, // Generate external source map
// sourcemap: 'inline', // Inline source map
// sourcemap: 'hidden' // Generate but don't reference
}
};
Plugins¶
Essential Plugins¶
# Install essential plugins
npm install --save-dev @rollup/plugin-node-resolve
npm install --save-dev @rollup/plugin-commonjs
npm install --save-dev @rollup/plugin-babel
npm install --save-dev @rollup/plugin-terser
Node Resolve Plugin¶
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
resolve({
browser: true, // Use browser field in package.json
preferBuiltins: false, // Don't prefer Node.js built-ins
extensions: ['.js', '.jsx', '.ts', '.tsx']
})
]
};
CommonJS Plugin¶
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
commonjs({
include: 'node_modules/**', // Convert CommonJS modules
exclude: ['node_modules/foo/**'], // Exclude specific modules
transformMixedEsModules: true // Handle mixed ES/CommonJS modules
})
]
};
Babel Plugin¶
import babel from '@rollup/plugin-babel';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
presets: [
['@babel/preset-env', {
targets: {
browsers: ['> 1%', 'last 2 versions']
}
}]
]
})
]
};
Terser Plugin (Minificación)¶
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
terser({
compress: {
drop_console: true, // Remove console.log
drop_debugger: true // Remove debugger statements
},
format: {
comments: false // Remove comments
}
})
]
};
Reemplace Plugin¶
import replace from '@rollup/plugin-replace';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
'__VERSION__': JSON.stringify(process.env.npm_package_version)
})
]
};
JSON Plugin¶
import json from '@rollup/plugin-json';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
json()
]
};
// Usage in code
import { version } from '../package.json';
console.log(version);
URL Plugin (Assets)¶
import url from '@rollup/plugin-url';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
url({
limit: 10 * 1024, // 10KB limit for inline
include: ['**/*.svg', '**/*.png', '**/*.jpg', '**/*.gif'],
emitFiles: true
})
]
};
Dependencias externas¶
Configuración externa básica¶
export default {
input: 'src/main.js',
external: ['lodash', 'react', 'react-dom'],
output: {
file: 'dist/bundle.js',
format: 'umd',
globals: {
'lodash': '_',
'react': 'React',
'react-dom': 'ReactDOM'
}
}
};
Dynamic External Function¶
export default {
input: 'src/main.js',
external: (id) => {
// Mark all node_modules as external
return id.includes('node_modules');
},
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
Peer Dependencies as External¶
import pkg from './package.json';
export default {
input: 'src/main.js',
external: Object.keys(pkg.peerDependencies || {}),
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
Tree Shaking¶
Enabling Tree Shaking¶
// Rollup automatically tree-shakes ES modules
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'es'
}
};
Tree Shaking with Side Effects¶
// package.json
{
"sideEffects": false // No side effects, safe to tree-shake
}
// Or specify files with side effects
{
"sideEffects": [
"*.css",
"./src/polyfills.js"
]
}
Preserving Side Effects¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'es'
},
treeshake: {
moduleSideEffects: false, // Assume no side effects
// moduleSideEffects: (id) => id.includes('polyfill')
}
};
Tree Shaking Ejemplo¶
// utils.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export function multiply(a, b) {
console.log('This has a side effect!');
return a * b;
}
// main.js
import { add } from './utils.js'; // Only 'add' will be included
console.log(add(2, 3));
Code Splitting¶
Importaciones dinámicas¶
// main.js
async function loadModule() {
const module = await import('./heavy-module.js');
return module.default();
}
// Rollup config
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
chunkFileNames: '[name]-[hash].js'
}
};
Manual Chunks¶
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
manualChunks: {
vendor: ['lodash', 'react'],
utils: ['src/utils/helpers.js', 'src/utils/constants.js']
}
}
};
Dynamic Manual Chunks¶
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
manualChunks: (id) => {
if (id.includes('node_modules')) {
return 'vendor';
}
if (id.includes('src/utils')) {
return 'utils';
}
}
}
};
Entry Point Splitting¶
export default {
input: {
main: 'src/main.js',
admin: 'src/admin.js',
vendor: 'src/vendor.js'
},
output: {
dir: 'dist',
format: 'es'
}
};
Watch Mode¶
Modo de reloj básico¶
Watch Configuration¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
watch: {
include: 'src/**',
exclude: 'node_modules/**',
clearScreen: false
}
};
Ver con Plugins¶
import livereload from 'rollup-plugin-livereload';
import serve from 'rollup-plugin-serve';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: !production
},
plugins: [
// ... other plugins
!production && serve({
open: true,
contentBase: 'dist',
port: 3000
}),
!production && livereload('dist')
]
};
Development vs Production¶
Configuración basada en el medio ambiente
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import replace from '@rollup/plugin-replace';
const production = process.env.NODE_ENV === 'production';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: !production
},
plugins: [
resolve(),
commonjs(),
replace({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
production && terser()
].filter(Boolean)
};
Archivos de Config separados¶
// rollup.config.dev.js
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: true
},
plugins: [
serve({
contentBase: 'dist',
port: 3000
}),
livereload('dist')
]
};
// rollup.config.prod.js
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
terser()
]
};
Package.json Scripts¶
{
"scripts": {
"dev": "rollup -c rollup.config.dev.js -w",
"build": "NODE_ENV=production rollup -c rollup.config.prod.js"
}
}
TipoScript Integration¶
TipoScript Plugin¶
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/main.ts',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
typescript({
tsconfig: './tsconfig.json'
})
]
};
TipoScript Configuration¶
// tsconfig.json
{
"compilerOptions": {
"target": "es2018",
"module": "esnext",
"lib": ["dom", "dom.iterable", "es6"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"declaration": true,
"outDir": "dist"
},
"include": [
"src"
]
}
```_
### TipoScript with Babel
```javascript
import typescript from '@rollup/plugin-typescript';
import babel from '@rollup/plugin-babel';
export default {
input: 'src/main.ts',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
typescript(),
babel({
babelHelpers: 'bundled',
extensions: ['.js', '.ts']
})
]
};
CSS y Activos
PostCSS Plugin¶
import postcss from 'rollup-plugin-postcss';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
postcss({
extract: true, // Extract to separate CSS file
minimize: true, // Minify CSS
sourceMap: true
})
]
};
SCSS/Sass Support¶
import postcss from 'rollup-plugin-postcss';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
postcss({
extract: 'styles.css',
use: ['sass']
})
]
};
Asset Handling¶
import url from '@rollup/plugin-url';
import copy from 'rollup-plugin-copy';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
url({
limit: 10 * 1024, // 10KB
include: ['**/*.svg', '**/*.png', '**/*.jpg'],
emitFiles: true
}),
copy({
targets: [
{ src: 'src/assets/images/*', dest: 'dist/images' },
{ src: 'src/assets/fonts/*', dest: 'dist/fonts' }
]
})
]
};
```_
## Library Development
### Configuración de la Biblioteca
```javascript
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import pkg from './package.json';
export default [
// ES module build
{
input: 'src/index.js',
external: Object.keys(pkg.peerDependencies || {}),
output: {
file: pkg.module,
format: 'es'
},
plugins: [
resolve(),
commonjs()
]
},
// CommonJS build
{
input: 'src/index.js',
external: Object.keys(pkg.peerDependencies || {}),
output: {
file: pkg.main,
format: 'cjs'
},
plugins: [
resolve(),
commonjs()
]
},
// UMD build
{
input: 'src/index.js',
output: {
file: pkg.browser,
format: 'umd',
name: 'MyLibrary',
globals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
},
plugins: [
resolve(),
commonjs(),
terser()
]
}
];
Package.json for Library¶
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"browser": "dist/index.umd.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "rollup -c",
"prepublishOnly": "npm run build"
},
"peerDependencies": {
"react": "^17.0.0",
"react-dom": "^17.0.0"
}
}
TipoScript Biblioteca¶
import typescript from '@rollup/plugin-typescript';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/index.ts',
output: [
{
file: 'dist/index.esm.js',
format: 'es'
},
{
file: 'dist/index.cjs.js',
format: 'cjs'
}
],
plugins: [
typescript({
declaration: true,
declarationDir: 'dist'
}),
resolve(),
commonjs()
]
};
Configuración avanzada¶
Custom Plugin¶
function myPlugin() {
return {
name: 'my-plugin',
buildStart(opts) {
console.log('Build started');
},
transform(code, id) {
if (id.endsWith('.special')) {
return `export default ${JSON.stringify(code)}`;
}
},
generateBundle(opts, bundle) {
console.log('Bundle generated');
}
};
}
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
myPlugin()
]
};
Construidos condicionales¶
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
const configs = [];
// Development build
if (process.env.NODE_ENV !== 'production') {
configs.push({
input: 'src/main.js',
output: {
file: 'dist/bundle.dev.js',
format: 'iife',
sourcemap: true
},
plugins: [resolve(), commonjs()]
});
}
// Production build
if (process.env.NODE_ENV === 'production') {
configs.push({
input: 'src/main.js',
output: {
file: 'dist/bundle.min.js',
format: 'iife'
},
plugins: [resolve(), commonjs(), terser()]
});
}
export default configs;
Multi-entry with Shared Dependencies¶
export default {
input: {
main: 'src/main.js',
admin: 'src/admin.js'
},
output: {
dir: 'dist',
format: 'es',
manualChunks: {
vendor: ['lodash', 'react'],
shared: ['src/utils/shared.js']
}
}
};
Performance Optimization¶
Bundle Analysis¶
# Install bundle analyzer
npm install --save-dev rollup-plugin-analyzer
# Use in config
import analyze from 'rollup-plugin-analyzer';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
analyze({
summaryOnly: true,
limit: 10
})
]
};
Optimize Dependencies
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
resolve({
preferBuiltins: false,
browser: true
}),
commonjs({
include: 'node_modules/**'
})
]
};
Minimizar el tamaño de la casa¶
import { terser } from 'rollup-plugin-terser';
import replace from '@rollup/plugin-replace';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production')
}),
terser({
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log', 'console.info']
}
})
]
};
Troubleshooting¶
Common Issues and Solutions¶
Dependencias Circulares¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
onwarn: (warning, warn) => {
if (warning.code === 'CIRCULAR_DEPENDENCY') {
console.warn('Circular dependency:', warning.message);
return;
}
warn(warning);
}
};
Dependencias externas no encontradas¶
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
resolve({
browser: true,
preferBuiltins: false
})
]
};
Problemas del módulo CommonJS¶
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
commonjs({
include: 'node_modules/**',
transformMixedEsModules: true
})
]
};
Memory Issues¶
Debug Configuration¶
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
onwarn: (warning, warn) => {
console.log('Warning:', warning);
warn(warning);
}
};
Buenas prácticas¶
Configuration Organization¶
// rollup.config.js
import { createConfig } from './config/rollup.common.js';
const configs = [
createConfig('es'),
createConfig('cjs'),
createConfig('umd')
];
export default configs;
// config/rollup.common.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
export function createConfig(format) {
return {
input: 'src/index.js',
output: {
file: `dist/bundle.${format}.js`,
format
},
plugins: [
resolve(),
commonjs()
]
};
}
Performance Best Practices¶
- Use módulos ES para un mejor afeitado de árboles
- Marcar dependencias externas para reducir el tamaño del paquete
- Activar la división del código** para aplicaciones grandes
- Use terser para la minificación de producción
- Analyze packs para identificar oportunidades de optimización
Development Best Practices¶
- Use modo de reloj para el desarrollo
- Mapas de fuentes* para depurar
Sube la recarga en vivo # para mejor DX¶
- Forro de configuración con ESLint
- Use TipoScript para una mejor seguridad tipo
Library Development Las mejores prácticas¶
- Proveer múltiples formatos** (S, CJS, UMD)
- Declaraciones genéricas TipoScript para usuarios de TipoScript Dependencias de los pares de mercado como externas
- Use versión semántica para versiones
- Test construye antes de publicar
-...
Summary¶
Rollup es un potente módulo que se destaca en la creación de paquetes optimizados para bibliotecas y aplicaciones. Las características principales incluyen:
- ES Módulo Primero: Soporte nativo para módulos ES con excelente afeitado de árboles
- Multiple Output Formats: Support for ES, CJS, UMD, IIFE, AMD y SystemJS
- Ecosistema de Plugin: Ecosistema rico de plugins para diversas transformaciones
- Code Splitting: Capacidades avanzadas de división de código
- Tree Shaking: Eliminación automática del código muerto TypeScript Support: Integración TipoScript de primera clase Library Friendly: Excelente para construir y distribuir bibliotecas
Al aprovechar las fortalezas de Rollup y seguir las mejores prácticas, puede crear paquetes altamente optimizados que sean perfectos tanto para el desarrollo de bibliotecas como para el desarrollo de aplicaciones.