72. Rollup 教程
1. Rollup 简介
Rollup 是一个 JavaScript 模块打包器,专注于创建更小、更高效的库和应用程序。与 Webpack 不同,Rollup 更注重代码的精简和性能,特别适合构建 JavaScript 库。
1.1 Rollup 的核心特性
- Tree Shaking:自动移除未使用的代码,减小打包体积
- ES 模块优先:原生支持 ES 模块,输出更简洁的代码
- 多种输出格式:支持输出 ES、CommonJS、UMD、AMD 等多种模块格式
- 插件生态系统:通过插件扩展功能
- 代码分割:支持动态导入和代码分割
1.2 Rollup 与 Webpack 的比较
| 特性 | Rollup | Webpack |
|---|---|---|
| 主要用途 | 库打包 | 应用打包 |
| Tree Shaking | 更高效 | 支持但相对复杂 |
| 配置复杂度 | 简单 | 复杂 |
| 输出体积 | 更小 | 相对较大 |
| 代码分割 | 支持 | 更强大 |
| 热模块替换 | 有限支持 | 强大支持 |
2. 安装与配置
2.1 安装 Rollup
首先,在项目中安装 Rollup 和相关插件:
# 使用 npm
npm install --save-dev rollup
# 使用 yarn
yarn add --dev rollup
# 使用 pnpm
pnpm add --save-dev rollup2.2 基本配置文件
在项目根目录创建 rollup.config.js 文件:
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
}
};2.3 配置 package.json 脚本
在 package.json 文件中添加构建脚本:
{
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w"
}
}3. 基本使用
3.1 处理 JavaScript 模块
创建 src/index.js 文件:
// 导入模块
import { add } from './utils.js';
// 导出模块
export const calculator = {
add,
multiply: (a, b) => a * b
};创建 src/utils.js 文件:
// 导出模块
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// 这个函数不会被打包,因为没有被使用
export const divide = (a, b) => a / b;3.2 多种输出格式
修改 rollup.config.js 文件,支持多种输出格式:
export default [
{
input: 'src/index.js',
output: {
file: 'dist/bundle.esm.js',
format: 'esm'
}
},
{
input: 'src/index.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs'
}
},
{
input: 'src/index.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLibrary'
}
}
];3.3 使用插件
安装常用插件:
npm install --save-dev @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-babel更新 rollup.config.js 文件:
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/bundle.js',
format: 'esm'
},
plugins: [
resolve(),
commonjs(),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**'
})
]
};4. 高级特性
4.1 Tree Shaking 优化
Rollup 的 Tree Shaking 功能会自动分析代码依赖,只打包被使用的代码。例如:
// src/index.js
import { add } from './utils.js';
// 只使用了 add 函数,subtract 和 divide 不会被打包
console.log(add(1, 2));4.2 代码分割
使用动态导入实现代码分割:
// src/index.js
export async function loadHeavyModule() {
const { default: heavyModule } = await import('./heavy-module.js');
return heavyModule;
}配置代码分割:
export default {
input: 'src/index.js',
output: {
dir: 'dist',
format: 'esm'
}
};4.3 外部依赖
配置外部依赖,避免将某些库打包进最终文件:
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
external: ['react', 'lodash']
};4.4 环境变量
使用 @rollup/plugin-replace 插件处理环境变量:
npm install --save-dev @rollup/plugin-replaceimport replace from '@rollup/plugin-replace';
export default {
// ... 其他配置
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
};5. 最佳实践
5.1 目录结构
推荐的目录结构:
├── dist/
├── src/
│ ├── index.js # 入口文件
│ ├── utils.js # 工具函数
│ └── components/ # 组件
├── rollup.config.js # Rollup 配置
└── package.json # 项目配置5.2 配置分离
对于复杂项目,可将配置分离为多个文件:
rollup.config.js:公共配置rollup.config.dev.js:开发环境配置rollup.config.prod.js:生产环境配置
5.3 性能优化
- 使用 ES 模块:优先使用 ES 模块语法,获得更好的 Tree Shaking 效果
- 合理配置外部依赖:避免打包大型库
- 使用缓存:启用 Rollup 的缓存功能
- 并行构建:对于多入口项目,考虑使用并行构建
5.4 代码质量
- 使用 ESLint:确保代码质量
- 使用 Prettier:保持代码风格一致
- 添加类型检查:对于 TypeScript 项目,使用 TypeScript 进行类型检查
6. 插件系统
6.1 常用插件
| 插件名称 | 功能 | 安装命令 |
|---|---|---|
| @rollup/plugin-node-resolve | 解析 node_modules 中的模块 | npm install --save-dev @rollup/plugin-node-resolve |
| @rollup/plugin-commonjs | 将 CommonJS 模块转换为 ES 模块 | npm install --save-dev @rollup/plugin-commonjs |
| @rollup/plugin-babel | 使用 Babel 转换代码 | npm install --save-dev @rollup/plugin-babel |
| @rollup/plugin-terser | 压缩 JavaScript 代码 | npm install --save-dev @rollup/plugin-terser |
| @rollup/plugin-typescript | 支持 TypeScript | npm install --save-dev @rollup/plugin-typescript |
| rollup-plugin-postcss | 处理 CSS 文件 | npm install --save-dev rollup-plugin-postcss |
| rollup-plugin-json | 导入 JSON 文件 | npm install --save-dev @rollup/plugin-json |
6.2 自定义插件
创建简单的自定义插件:
// rollup.config.js
function myPlugin() {
return {
name: 'my-plugin',
transform(code, id) {
// 转换代码
return code.replace(/console\.log\(['"](.+)['"]\)/g, '// console.log("$1")');
}
};
}
export default {
// ... 其他配置
plugins: [
myPlugin()
]
};7. 示例项目
7.1 基本库项目
7.1.1 项目结构
├── dist/
├── src/
│ ├── index.js
│ ├── math.js
│ └── string.js
├── rollup.config.js
└── package.json7.1.2 源代码
// src/math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => a / b;
// src/string.js
export const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
export const truncate = (str, length) => str.length > length ? str.slice(0, length) + '...' : str;
// src/index.js
import * as math from './math.js';
import * as string from './string.js';
export default {
...math,
...string
};
export { math, string };7.1.3 Rollup 配置
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
export default [
{
input: 'src/index.js',
output: {
file: 'dist/bundle.esm.js',
format: 'esm'
},
plugins: [resolve(), commonjs()]
},
{
input: 'src/index.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs'
},
plugins: [resolve(), commonjs()]
},
{
input: 'src/index.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyUtils'
},
plugins: [resolve(), commonjs(), terser()]
}
];7.1.4 构建命令
npm run build7.2 带有代码分割的项目
7.2.1 源代码
// src/index.js
export async function loadMathModule() {
const { add, multiply } = await import('./math.js');
return { add, multiply };
}
export async function loadStringModule() {
const { capitalize } = await import('./string.js');
return { capitalize };
}7.2.2 Rollup 配置
export default {
input: 'src/index.js',
output: {
dir: 'dist',
format: 'esm'
}
};8. 常见问题与解决方案
8.1 Tree Shaking 不生效
问题:未使用的代码没有被移除
解决方案:
- 确保使用 ES 模块语法
- 检查插件配置是否正确
- 避免使用副作用较大的代码
8.2 外部依赖处理
问题:外部依赖被打包进最终文件
解决方案:
- 在
external选项中正确配置外部依赖 - 对于 UMD 格式,使用
globals选项指定全局变量
8.3 动态导入问题
问题:动态导入不工作
解决方案:
- 确保输出格式支持动态导入(如 esm、amd)
- 使用
output.dir而不是output.file
8.4 兼容性问题
问题:打包后的代码在某些环境下不工作
解决方案:
- 使用 Babel 转换代码
- 选择合适的输出格式
- 添加必要的 polyfill
9. 总结
Rollup 是一个专注于代码精简和性能的 JavaScript 模块打包器,特别适合构建 JavaScript 库。通过本教程的学习,你应该已经掌握了:
- Rollup 的核心概念和基本使用方法
- 如何配置 Rollup 处理不同类型的文件
- 如何使用 Rollup 的高级特性如 Tree Shaking 和代码分割
- Rollup 的最佳实践和性能优化技巧
- 如何使用和开发 Rollup 插件
Rollup 的设计理念是"做一件事并做好它",它在库打包方面的表现非常出色。对于需要构建小型、高效的 JavaScript 库的开发者来说,Rollup 是一个理想的选择。