Rollup 构建指南 📦
简介
Rollup 是一个 JavaScript 模块打包器,专注于构建高效的库和应用程序。它原生支持 ES 模块(ESM),是构建现代 JavaScript 库的理想选择。
- ES Module 原生支持 🚀
- 更好的 Tree Shaking 🌳
- 更小的包体积 📦
- 更清晰的代码结构 🎨
项目初始化
基础配置
bash
# 创建项目
mkdir my-rollup-project
cd my-rollup-project
npm init -y
# 安装 rollup 相关依赖
npm install rollup @rollup/plugin-node-resolve @rollup/plugin-typescript -D
npm install typescript tslib @types/node -Djavascript
import resolve from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import { defineConfig } from 'rollup';
export default defineConfig({
input: 'src/main.ts', // 入口文件
output: {
dir: 'dist', // 输出目录
format: 'es', // 使用 ES 模块格式
sourcemap: true // 生成 sourcemap
},
plugins: [
resolve(), // 解析第三方模块
typescript({ // TypeScript 配置
module: 'ESNext' // 确保 TypeScript 输出 ES 模块
})
]
});json
{
"name": "my-rollup-project",
"version": "1.0.0",
"type": "module", // 声明使用 ES 模块
"scripts": {
"dev": "rollup -c -w",
"build": "rollup -c",
"build:prod": "rollup -c --environment NODE_ENV:production"
}
}json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext", // 使用 ES 模块
"moduleResolution": "bundler", // 使用新的模块解析策略
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}ES 模块最佳实践
文件扩展名
- 使用
.mjs扩展名明确表示 ES 模块 - 配置文件使用
rollup.config.mjs - TypeScript 文件仍使用
.ts扩展名
- 使用
导入导出语法
typescript
// ✅ 推荐的写法
export const hello = () => 'Hello';
export default class MyClass {};
// ❌ 避免的写法
module.exports = {};
const { hello } = require('./hello');- 动态导入
typescript
// ✅ 使用动态导入
const module = await import('./module.js');
// ❌ 避免使用 require
const module = require('./module');模块解析
注意事项
- 总是使用完整的文件扩展名
typescript
// ✅ 推荐的写法
import { hello } from './hello.js';
import { type User } from './types.ts';
// ❌ 避免的写法
import { hello } from './hello';- 使用 package.json 的 exports 字段
json
{
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}
}- 路径别名配置
javascript
import alias from '@rollup/plugin-alias';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default {
plugins: [
alias({
entries: [
{
find: '@',
replacement: path.resolve(__dirname, 'src')
}
]
})
]
}第三方依赖处理
依赖处理建议
- 优先使用提供 ES 模块的包
json
{
"dependencies": {
"lodash-es": "^4.17.21", // ✅ ES 模块版本
"lodash": "^4.17.21" // ❌ CommonJS 版本
}
}- 外部化第三方依赖
javascript
export default {
external: [
/node_modules/,
'lodash-es'
]
}- 使用 importAssertions 处理 JSON
typescript
import config from './config.json' assert { type: 'json' };常用插件
核心插件
基础插件
| 插件 | 用途 | 安装命令 |
|---|---|---|
| @rollup/plugin-node-resolve | 解析第三方模块 | npm i -D @rollup/plugin-node-resolve |
| @rollup/plugin-commonjs | 转换 CommonJS 模块 | npm i -D @rollup/plugin-commonjs |
| @rollup/plugin-typescript | TypeScript 支持 | npm i -D @rollup/plugin-typescript |
| @rollup/plugin-babel | Babel 转换 | npm i -D @rollup/plugin-babel |
| @rollup/plugin-alias | 路径别名 | npm i -D @rollup/plugin-alias |
| @rollup/plugin-json | JSON 文件支持 | npm i -D @rollup/plugin-json |
开发优化
javascript
import { defineConfig } from 'rollup';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
export default defineConfig({
input: 'src/main.ts',
output: {
dir: 'dist',
format: 'es',
sourcemap: true
},
plugins: [
resolve(),
commonjs(),
typescript(),
serve({
open: true,
contentBase: ['dist', 'public'],
port: 3000
}),
livereload('dist')
]
});javascript
import { defineConfig } from 'rollup';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import terser from '@rollup/plugin-terser';
import cleanup from 'rollup-plugin-cleanup';
export default defineConfig({
input: 'src/main.ts',
output: {
dir: 'dist',
format: 'es',
sourcemap: true
},
plugins: [
resolve(),
commonjs(),
typescript(),
cleanup(),
terser()
]
});高级配置
多入口配置
多入口打包
javascript
export default {
input: {
main: 'src/main.ts',
worker: 'src/worker.ts'
},
output: {
dir: 'dist',
format: 'es',
sourcemap: true,
entryFileNames: '[name].js'
}
}外部依赖
外部依赖配置
javascript
export default {
// ... 其他配置
external: ['lodash', 'react', 'react-dom'],
output: {
globals: {
'lodash': '_',
'react': 'React',
'react-dom': 'ReactDOM'
}
}
}代码分割
动态导入示例
typescript
// src/main.ts
async function loadModule() {
const { hello } = await import('./hello');
hello();
}
// rollup.config.js
export default {
input: 'src/main.ts',
output: {
dir: 'dist',
format: 'es',
sourcemap: true,
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
}
}
}
}路径别名
路径别名配置
- 安装必要的插件:
bash
npm install -D @rollup/plugin-alias- 配置 rollup.config.js:
javascript
import alias from '@rollup/plugin-alias';
import path from 'path';
export default {
// ... 其他配置
plugins: [
alias({
entries: [
{
find: '@',
replacement: path.resolve(__dirname, 'src')
}
]
})
]
}- 确保 tsconfig.json 中也配置了相应的路径:
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}环境配置
环境变量
javascript
import { defineConfig } from 'rollup';
import replace from '@rollup/plugin-replace';
export default defineConfig({
// ... 其他配置
plugins: [
replace({
preventAssignment: true,
values: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(process.env.API_URL)
}
})
]
});bash
API_URL=http://localhost:3000bash
API_URL=https://api.example.com性能优化
优化建议
Tree Shaking
- 使用 ES 模块语法
- 避免副作用
- 使用
"sideEffects": false或指定有副作用的文件
代码分割
- 使用动态导入
- 配置
manualChunks - 提取公共依赖
构建优化
- 使用 terser 压缩代码
- 配置 external 减小包体积
- 使用 sourcemap 优化调试
常见问题
常见问题解决
模块解析问题
javascript// 检查 plugin-node-resolve 配置 resolve({ extensions: ['.js', '.ts'], preferBuiltins: true })CommonJS 模块问题
javascript// 配置 plugin-commonjs commonjs({ transformMixedEsModules: true, include: 'node_modules/**' })TypeScript 路径别名
javascript// 同时配置 rollup 和 typescript typescript({ tsconfig: './tsconfig.json' })
部署配置
部署检查清单
- 环境变量配置
- 代码压缩
- Source Map 处理
- 静态资源处理
- 缓存策略
- 错误处理
推荐工具
开发工具
- rollup-plugin-visualizer - 包大小分析
- rollup-plugin-serve - 开发服务器
- rollup-plugin-livereload - 热重载
- @rollup/plugin-terser - 代码压缩
- rollup-plugin-cleanup - 代码清理
Node.js 后端项目注意事项
当使用 Rollup 构建 Node.js 后端项目(如 Express 应用)时,需要特别注意:
- 安装必要的插件:
bash
# 安装 CommonJS 支持插件
npm install -D @rollup/plugin-commonjs- 更新 rollup.config.mjs:
javascript
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import { defineConfig } from 'rollup';
export default defineConfig({
input: 'src/main.ts',
output: {
dir: 'dist',
format: 'cjs', // Node.js 环境使用 CommonJS 格式
sourcemap: true
},
plugins: [
resolve({
preferBuiltins: true // 优先使用 Node.js 内置模块
}),
commonjs({
extensions: ['.js', '.ts'] // 需要转换的文件扩展名
}),
typescript({
module: 'ESNext'
})
],
external: [
'express', // 将 express 标记为外部依赖
/node_modules/ // 所有 node_modules 中的包都作为外部依赖
]
});- package.json 配置:
json
{
"type": "module", // 源码使用 ES 模块
"main": "dist/main.js", // 输出 CommonJS 格式
"dependencies": {
"express": "^4.18.2"
}
}- 源码中的导入方式:
typescript
// ✅ 使用 ES 模块语法导入
import express from 'express';
import type { Request, Response } from 'express';
const app = express();
// 其他代码...为什么需要这样配置?
- Node.js 生态中仍然有大量 CommonJS 模块(如 Express)
- 虽然我们的源码使用 ES 模块语法,但构建后的代码需要兼容 Node.js 环境
- 使用
format: 'cjs'确保输出的代码可以在 Node.js 中正常运行 - 使用
external可以避免打包 node_modules 中的依赖,减小包体积
常见问题
"default" is not exported
- 这通常是因为 CommonJS 模块没有默认导出
- 使用
@rollup/plugin-commonjs可以解决
Cannot use import statement outside a module
- 确保 package.json 中设置了
"type": "module" - 或者使用 .mjs 扩展名
- 确保 package.json 中设置了
模块解析问题
- 使用
preferBuiltins: true优先使用 Node.js 内置模块 - 正确配置 external 选项避免打包不必要的依赖
- 使用