组件库开发
项目初始化
npm init -y
# 安装 rollup 打包插件
npm i -D rollup新建 src/index.js 文件
console.log("Hello World!!")
export default {}创建配置文件 rollup.config.dev.js
const path = require("path")
const inputPath = path.resolve(__dirname, "./src/index.js")
const outputPath = path.resolve(__dirname, "./dist/datav.js")
console.log("inputPath", inputPath)
module.exports = {
input: inputPath,
output: {
file: outputPath,
format: "umd",
name: "datav"
}
}添加脚本并执行 pnpm dev
{
"name": "datav-libs",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "rollup -wc rollup.config.dev.js",
"build": "rollup -c rollup.config.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"packageManager": "pnpm@9.12.2+sha1.3012e6dd27e70ec4e185be062e8a124523dccfc4",
"devDependencies": {
"rollup": "^4.42.0"
}
}模块化标准
原打包文件 src/index.js
console.log("Hello World!!")
export default {}- umd 标准
;(function (global, factory) {
typeof exports === "object" && typeof module !== "undefined"
? (module.exports = factory())
: typeof define === "function" && define.amd
? define(factory)
: ((global = typeof globalThis !== "undefined" ? globalThis : global || self), (global.datav = factory()))
})(this, function () {
"use strict"
console.log("Hello World!!")
var index = {}
return index
})html 使用的方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<script src="../dist/datav.js"></script>
</head>
<body></body>
</html>- cjs 标准
"use strict"
console.log("Hello World!!")
var index = {}
module.exports = index打包后的 cjs 模块,浏览器不可以直接使用,需要使用 webpack 工具打包成 umd 文件
- es
console.log("Hello World!!")
var index = {}
export { index as default }html 使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<script src="../dist/datav.js" type="module"></script>
</head>
<body></body>
</html>rollup-plugin-node-resolve
rollup-plugin-node-resolve 是 Rollup 的核心插件,用于解析第三方模块的路径(如 node_modules 中的依赖),确保 Rollup 能够正确找到并打包这些模块。它解决了 Rollup 默认不处理 node_modules 依赖的问题,是构建复杂项目时的必备工具
- 解析
node_modules中的模块 Rollup 默认只处理相对路径(如./utils.js),而无法直接识别import lodash from 'lodash'这样的模块引用。该插件会按照 Node.js 的模块解析规则(如main、module、exports字段)定位依赖。 - 支持模块扩展名自动补全
自动尝试添加
.js、.json、.node等扩展名(类似 Webpack 的resolve.extensions) - 处理子路径和深层依赖
例如
import 'lodash/get'或嵌套的node_modules依赖 - 自定义主入口字段
可优先选择
module(ESM)或main(CJS)等字段,优化 Tree Shaking
基本使用
npm install -D rollup-plugin-node-resolve在 Rollup 配置文件中引入插件:
import resolve from 'rollup-plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
plugins: [
resolve()
]
};常用配置选项:
| 选项 | 说明 |
|---|---|
mainFields | 指定模块入口字段的优先级(默认 ['module', 'main'])。 |
extensions | 解析时尝试的扩展名(默认 ['.js', '.json', '.node'])。 |
modulesOnly | 是否仅解析 ES Modules(默认 false,也支持 CJS)。 |
jail | 将解析限制在指定目录内(如 jail: '/src')。 |
dedupe | 强制使用同一版本的依赖(如 dedupe: ['lodash'])。 |
preferBuiltins | 是否优先使用 Node.js 内置模块(如 fs,默认 true)。 |
示例:自定义配置:
resolve({
mainFields: ['module', 'main'], // 优先使用 ESM 入口
extensions: ['.mjs', '.js', '.jsx'], // 支持更多扩展名
modulesOnly: true, // 仅打包 ESM 模块
dedupe: ['react', 'react-dom'] // 避免重复依赖
})与其他插件的协作
-
与
@rollup/plugin-commonjs搭配 如果依赖是 CommonJS 格式(如 Lodash),需先用commonjs插件转换为 ESM:JavaScriptimport commonjs from '@rollup/plugin-commonjs'; import resolve from 'rollup-plugin-node-resolve'; plugins: [ resolve(), commonjs() ] -
与
rollup-plugin-babel搭配 在解析模块后使用 Babel 转译:JavaScriptimport babel from 'rollup-plugin-babel'; plugins: [ resolve(), babel({ presets: ['@babel/preset-env'] }) ]
@babel/node 全局使用
@babel/node 是 Babel 提供的命令行工具,它允许你直接使用 Babel 转译和运行 Node.js 脚本(支持 ES6+ 语法、JSX、TypeScript 等)。它相当于一个集成了 Babel 的 node 替代品,适合开发阶段的快速调试和原型开发。主要用途就是将 es6 的代码转换为 es5 的代码,babel 官网
- 实时转译 在运行
.js、.jsx、.ts等文件时,自动通过 Babel 转译代码(基于项目中的 Babel 配置,如.babelrc或babel.config.js) - 支持最新语法 允许直接使用 ES Modules (
import/export)、装饰器、类属性等尚未被 Node.js 原生支持的语法 - REPL 环境 提供交互式 REPL 环境(类似原生
node的 REPL),支持实验性语法
全局安装模块:
npm i -g @babel/node
npm i -g @babel/core注意:
@babel/node依赖@babel/core需同时安装
基本用法
-
直接运行文件 通过
babel-node命令执行脚本:bashbabel-node script.js -
REPL 模式 启动支持 Babel 转译的交互式环境:
bashzhangzhengyang@zhangzhengyang datav-libs % babel-node babel > require("./src/index.js") Hello World!! {} babel > require("./src/index.js") {} babel > require("./src/index.js") {} babel > -
结合 Babel 配置 确保项目根目录有 Babel 配置文件(如
.babelrc),例如:bash{ "presets": ["@babel/preset-env"] }
常见选项:
| 选项 | 说明 |
|---|---|
--presets | 指定使用的 Babel preset(覆盖配置) |
--extensions | 指定处理的文件扩展名(默认 .js, .jsx, .es6, .es, .mjs) |
--ignore | 忽略的文件/目录(如 --ignore "node_modules") |
示例:
npx babel-node --presets @babel/preset-env,@babel/preset-react src/app.jsx不适用于生产环境 @babel/node 每次运行都会实时转译代码,性能较差。生产环境应先用 babel-cli 或构建工具(如 Webpack)预编译代码,再用原生 node 运行
与 ts-node 的区别:
@babel/node:通过 Babel 转译(支持 JS/TS,但类型检查需额外配置)ts-node:专为 TypeScript 设计,集成类型检查,通常对 TS 项目更友好
.babelrc 文件
需要在项目根目录创建 .babelrc 文件和安装 @babel/preset-env 模块
npm i -D @babel/preset-env.babelrc 文件内容:
{
"presets": [
"@babel/env"
]
}@babel/plugin-transform-runtime
@babel/plugin-transform-runtime 是 Babel 的一个核心插件,用于优化代码转译过程中的**辅助函数(helper functions)和内置特性(如 Promise、Symbol 等)**的复用,从而减少代码体积、避免全局污染,并提升兼容性。它通常与 @babel/runtime 配合使用
核心功能
- 复用辅助函数
- 问题:Babel 转译语法(如
class、async/await)时会自动生成辅助函数(如_classCallCheck、_asyncToGenerator)。默认情况下,这些函数会直接插入到每个文件中,导致代码冗余 - 解决:
transform-runtime将这些辅助函数改为从@babel/runtime中按需引入,减少重复代码
- 避免全局污染
- 问题:转译
Promise、Symbol等新 API 时,Babel 默认会通过全局注入 polyfill(如core-js),可能污染全局环境 - 解决:
transform-runtime以模块化方式引入这些 API,避免直接修改全局对象
- 支持沙箱环境
- 适合开发库(Library)或工具包,确保代码不会因 polyfill 影响宿主环境
需同时安装插件和运行时依赖:
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime # 必须作为生产依赖注意:
@babel/runtime是生产依赖,因为转译后的代码会直接引用它
修改配置文件 rollup.config.dev.js
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3, // 可选:指定 core-js 版本(默认 false)
"helpers": true, // 是否复用辅助函数(默认 true)
"regenerator": true // 是否复用 generator 函数(默认 true)
}
]
]
}关键配置选项:
| 选项 | 说明 |
|---|---|
corejs | 使用 core-js 的版本(false、2、3)。需额外安装 @babel/runtime-corejs3 |
helpers | 是否复用 Babel 的辅助函数(如 _classCallCheck),默认 true |
regenerator | 是否复用 regenerator-runtime(转译 async/await),默认 true |
useESModules | 是否使用 ES Modules 语法引入 helpers(优化 Tree Shaking) |
示例对比
未使用 transform-runtime,转译后的代码直接插入辅助函数:
// 输入代码
class Foo {}
// 输出代码
function _classCallCheck(instance, Constructor) {
/*...*/
}
var Foo = function Foo() {
_classCallCheck(this, Foo)
}使用 transform-runtime,辅助函数从 @babel/runtime 引入:
// 输出代码
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
var Foo = function Foo() {
_classCallCheck(this, Foo);
};tree-shaking 机制
Rollup 的 Tree-Shaking(摇树优化)是一种通过静态分析移除 JavaScript 代码中未使用部分(dead code)的机制。它依赖于 ES Modules(ESM)的静态结构特性,能够显著减少打包体积,提升运行效率
核心原理
静态分析的基础:ES Modules
- ESM 的静态特性:
import/export语句必须在模块顶层声明(不能动态生成),这使得 Rollup 在打包时能明确追踪模块的依赖关系和导出/导入情况。 - 对比 CommonJS:CommonJS 的
require()是动态的,无法在构建时确定依赖关系,因此传统工具(如 Webpack 4 之前)难以优化。
作用域与副作用分析
- 作用域隔离:Rollup 分析每个模块的导入导出,标记未被引用的导出。
- 副作用检测:通过静态代码分析(或手动注解)判断模块是否有副作用(如修改全局变量、触发 IIFE 等)。无副作用的代码更容易被移除
工作流程
- 依赖图谱构建 Rollup 从入口文件出发,递归分析所有
import语句,生成完整的依赖关系图 - 标记活跃代码
- 从入口开始,标记所有被直接或间接引用的导出(如函数、变量、类)
- 未被引用的导出标记为“未使用”(例如未使用的工具函数或冗余代码)
- 副作用检查
- 如果模块未被标记为“有副作用”(如
package.json中"sideEffects": false),则安全移除未引用的代码 - 无法确定副作用的代码默认保留(保守策略)
- 如果模块未被标记为“有副作用”(如
- 生成最终包 仅包含被标记的活跃代码和必要的依赖,剔除未使用的部分
关键配置与优化技巧
- 启用 Tree-Shaking 的条件
使用 ESM 格式:确保源码和依赖的第三方库提供 ESM 版本(优先 "module" 字段)。修改 Rollup 配置:默认启用,无需额外设置,但需配合以下优化:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm', // 输出 ESM 格式以支持下游进一步优化
},
treeshake: true, // 默认开启,可配置详细规则
};- 手动标记副作用
在 package.json 中声明:
{
"sideEffects": false, // 整个库无副作用
// 或指定有副作用的文件
"sideEffects": ["**/*.css", "**/*.global.js"]
}- 代码注释:在模块顶部添加
/*#__PURE__*/标记纯函数调用(如/*#__PURE__*/ someFunction())
- 第三方库的优化
- 优先选择 ESM 版本:如
lodash-es替代lodash。 - 排除无 Tree-Shaking 的库:某些库(如
jQuery)因大量副作用需手动添加到external
实际效果示例:
- 未优化前的代码
// utils.js
export const usedFunc = () => console.log('I am used');
export const unusedFunc = () => console.log('I am unused');
// main.js
import { usedFunc } from './utils';
usedFunc();- 使用 Tree-Shaking 后输出,
unusedFunc被完全移除,因为它未被引用且无副作用
// dist/bundle.js
const usedFunc = () => console.log('I am used');
usedFunc();常见问题与解决
为什么某些代码未被移除?
- 原因:模块被标记为有副作用,或 Rollup 无法静态分析动态代码(如
eval()) - 解决:检查
sideEffects配置,或使用/*#__PURE__*/标记纯函数
如何验证 Tree-Shaking 效果?
- 使用 Rollup 的
output.hoistTransitiveImports: false查看详细依赖 - 分析输出文件(如通过
rollup-plugin-visualizer生成依赖图)
如何处理 CommonJS 依赖?
- 使用
@rollup/plugin-commonjs转换 CJS 为 ESM,但可能损失部分优化效果
external 属性
external 是 Rollup 配置中的重要属性,用于声明某些模块不打包到最终的输出文件中,而是作为外部依赖(如通过 <script> 标签引入的 CDN 资源或 Node.js 的 require/import)。它适用于以下场景:
- 避免重复打包(如
react、lodash等公共库) - 依赖由运行时环境提供(如浏览器全局变量
jQuery或 Node.js 内置模块fs) - 优化构建速度(跳过大型库的解析和打包)
基本用法
在 Rollup 配置中,external 可以接受以下类型的值:
- 字符串(匹配模块名或路径)
- 正则表达式(匹配一类模块)
- 函数(动态判断是否外部化)
示例配置:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
external: [
'react', // 直接声明模块名
/^lodash\/.+/, // 正则匹配子路径(如 lodash/get)
(id) => id.includes('jquery') // 函数动态判断
]
};- 字符串匹配
- 精确匹配模块名:
external: ['react', 'lodash']会排除所有import 'react'或import 'lodash'的引用 - 路径匹配:
external: ['src/utils']排除本地文件
- 正则表达式匹配
- 排除所有
lodash的子路径:external: [/^lodash\/.+$/]。效果:import 'lodash/get'会被外部化,但import 'lodash'不会(需单独声明)
- 函数动态判断
-
根据模块 ID 动态决策:
JavaScriptexternal: (id) => { // 排除 node_modules 中的依赖或 Node.js 内置模块 return id.startsWith('node:') || /node_modules/.test(id); }
不同场景下的配置
- 浏览器环境(CDN 引入)
假设 react 和 lodash 通过 <script> 标签全局挂载:
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/lodash@4/lodash.min.js"></script>Rollup 配置:
external: ['react', 'lodash'],
output: {
format: 'iife',
globals: {
react: 'React', // 将 import 'react' 映射到全局变量 React
lodash: '_' // 将 import 'lodash' 映射到全局变量 _
}
}- Node.js 内置模块
排除 fs、path 等内置模块:
external: ["fs", "path", "node:events"]- peerDependencies(库开发)
开发一个库时,声明 peerDependencies 不打包:
external: Object.keys(require('./package.json').peerDependencies)注意事项
- 必须配合
output.globals(UMD/IIFE 格式)
如果输出格式为 umd 或 iife,需通过 globals 指定外部模块的全局变量名,否则运行时会报错:
output: {
format: 'umd',
globals: {
react: 'React',
lodash: '_'
}
}- 与
commonjs插件的协作
如果依赖是 CommonJS 模块(如 lodash),需先通过 @rollup/plugin-commonjs 转换,再外部化:
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
export default {
plugins: [
resolve(),
commonjs()
],
external: ['lodash']
};- 避免误排除
错误的 external 配置会导致运行时缺失依赖。可通过以下方式调试:
- 检查打包后的文件是否包含
require或import语句 - 使用
rollup-plugin-visualizer分析依赖图
示例:修改 rollup.js 的配置文件:
import resolve from "rollup-plugin-node-resolve"
export default {
input: "./src/plugin/main.js",
output: [
{
file: "./dist/index-plugin-cjs.js",
format: "cjs"
},
{
file: "./dist/index-plugin-es.js",
format: "es"
}
],
plugins: [resolve()],
external: ["vue"]
}重新打包:
rollup -c rollup.plugin.config.js查看 dist/index-plugin-es.js,可以看到虽然使用 resolve 插件,vue 库仍被当做外部库处理
@rollup/plugin-commonjs 插件
@rollup/plugin-commonjs 是 Rollup 的核心插件,用于将 CommonJS (CJS) 模块转换为 ES Modules (ESM),使 Rollup 能够正确解析和打包依赖项。由于 Rollup 原生仅支持 ESM,而许多 npm 包(如 lodash、react 等)仍采用 CommonJS 格式,因此该插件在 Rollup 生态中至关重要
npm install @rollup/plugin-commonjs -D基本使用
基本配置:
// rollup.config.js
import commonjs from '@rollup/plugin-commonjs';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
plugins: [
commonjs() // 默认配置
]
};常用配置选项:
| 选项 | 说明 |
|---|---|
include | 指定需要转换的模块(如 include: /node_modules/)。 |
exclude | 排除不需要转换的模块(如 exclude: /node_modules\/lodash-es/)。 |
extensions | 指定解析的文件扩展名(默认 ['.js', '.cjs'])。 |
ignoreGlobal | 是否忽略全局变量(如 process、Buffer),默认 false。 |
sourceMap | 是否生成 sourcemap,默认 true。 |
transformMixedEsModules | 是否转换混合 ESM/CJS 模块(如 import + module.exports),默认 false。 |
dynamicRequireTargets | 指定动态 require() 的目标模块(如 ['node_modules/**/*.js'])。 |
示例:高级配置
commonjs({
include: /node_modules/, // 仅转换 node_modules 中的 CJS 模块
exclude: ['node_modules/lodash-es'], // 排除已为 ESM 的 lodash-es
extensions: ['.js', '.cjs'], // 处理 .js 和 .cjs 文件
ignoreGlobal: true, // 不注入全局变量
dynamicRequireTargets: [
'node_modules/debug/**/*.js' // 处理 debug 模块的动态 require
]
})常见问题与解决
- 动态
require()报错
问题:某些库(如 debug)使用动态 require(),Rollup 默认无法解析
解决:通过 dynamicRequireTargets 指定目标模块:
commonjs({
dynamicRequireTargets: ['node_modules/debug/**/*.js']
})- 混合 ESM/CJS 模块报错
问题:模块同时使用 import 和 module.exports,导致转换失败
解决:启用 transformMixedEsModules:
commonjs({
transformMixedEsModules: true
})- 全局变量缺失(如
process)
问题:浏览器环境缺少 Node.js 全局变量(如 process)。
解决:
-
使用
rollup-plugin-inject注入变量:JavaScriptimport inject from '@rollup/plugin-inject'; plugins: [ commonjs(), inject({ process: 'process' }) // 注入 process ] -
或通过
@rollup/plugin-replace替换:javascriptimport replace from "@rollup/plugin-replace" plugins: [replace({ "process.env.NODE_ENV": JSON.stringify("production") })]
@rollup/plugin-babel
@rollup/plugin-babel 是 Rollup 的官方插件,用于在打包过程中通过 Babel 转译 JavaScript 代码,支持 ES6+ 语法、JSX、TypeScript 等新特性,同时兼容旧浏览器或 Node.js 环境。它是 Rollup 生态中实现代码兼容性的核心工具之一
- 语法降级 将 ES6+ 代码(如
箭头函数、async/await、类属性)转换为 ES5 语法 - JSX/TSX 转换 支持 React/Vue 的 JSX 或 TypeScript 语法转译
- 按需 Polyfill 配合
@babel/preset-env按目标环境自动引入必要的 polyfill - 代码优化 移除类型注解(TypeScript)、死代码(Dead Code Elimination)
- Sourcemap 支持 生成准确的 Sourcemap,便于调试
npm i @rollup/plugin-babel -D修改配置文件,增加 babel 插件的引用:
const path = require("path")
// 将项目中的依赖打包进包中
const resolve = require("rollup-plugin-node-resolve")
const vuePlugin = require("rollup-plugin-vue")
const postcss = require("rollup-plugin-postcss")
const { babel } = require("@rollup/plugin-babel")
// const commonjs = require("rollup-plugin-commonjs")
const json = require("rollup-plugin-json")
const inputPath = path.resolve(__dirname, "./src/index.js")
const outputUmdPath = path.resolve(__dirname, "./dist/datav.js")
const outputEsPath = path.resolve(__dirname, "./dist/datav.es.js")
console.log("inputPath", inputPath)
module.exports = {
input: inputPath,
output: [
{
file: outputUmdPath,
format: "umd",
name: "datav",
globals: {
vue: "Vue" // 指定全局变量
}
},
{
file: outputEsPath,
format: "es"
}
],
plugins: [
resolve(),
// commonjs(),
babel({
exclude: "node_modules/**",
babelHelpers: "runtime", // 替换为新的配置
plugins: [
[
"@babel/transform-runtime",
{
regenerator: true // 默认false
}
]
]
}),
json(),
vuePlugin(),
postcss({
plugins: []
})
],
external: ["vue"]
}rollup-plugin-json 插件
默认情况下 rollup.js 不支持导入 json 模块,需要使用 json 插件来支持
npm i -D rollup-plugin-json修改配置文件:
import resolve from "rollup-plugin-node-resolve"
import commonjs from "rollup-plugin-commonjs"
import babel from "rollup-plugin-babel"
import json from "rollup-plugin-json"
export default {
input: "./src/plugin/main-json.js",
output: [
{
file: "./dist/index-plugin-cjs.js",
format: "cjs"
},
{
file: "./dist/index-plugin-es.js",
format: "es"
}
],
plugins: [resolve(), commonjs(), babel(), json()]
}重新打包:rollup -c rollup.plugin.config.js。查看dist/index-plugin-cjs.js源码,可以看到 json 文件被解析为一个对象进行处理
var name = "rollup-test"
var version = "1.0.0"
var description = ""
var main = "index.js"
var scripts = {
test: 'echo "Error: no test specified" && exit 1'
}
var author = ""
var license = "ISC"
var devDependencies = {
"@babel/core": "^7.1.6",
"@babel/plugin-external-helpers": "^7.0.0",
"@babel/preset-env": "^7.1.6",
rollup: "^0.67.3",
"rollup-plugin-babel": "^4.0.3",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-json": "^3.1.0",
"rollup-plugin-node-resolve": "^3.4.0"
}
var dependencies = {
epubjs: "^0.3.80",
loadsh: "^0.0.3",
"sam-test-data": "^0.0.4",
"sam-test-data-cjs": "^0.0.1",
"sam-test-data-es": "^0.0.1",
"sam-test-data-umd": "^0.0.1"
}
var json = {
name: name,
version: version,
description: description,
main: main,
scripts: scripts,
author: author,
license: license,
devDependencies: devDependencies,
dependencies: dependencies
}
console.log(json.name, json.main)@rollup/plugin-terser
@rollup/plugin-terser 是 Rollup 的官方插件,用于压缩(Minify)和混淆(Obfuscate)JavaScript 代码,显著减少打包体积并提升运行时性能。它基于 Terser(UglifyJS 的现代替代品),支持 ES6+ 语法,是生产环境构建的必备工具
- 代码压缩
- 移除空格、注释、无效代码。
- 缩短变量名(如
longVariableName→a) - 优化表达式(如
!!a→a)
- Dead Code Elimination 结合 Rollup 的 Tree-Shaking 移除未使用的代码
- ES6+ 支持 正确处理
箭头函数、const/let、类等新语法 - Sourcemap 生成 生成压缩后的 Sourcemap,便于调试生产环境代码
- 多线程压缩 支持并行处理,提升构建速度。
npm install --save-dev @rollup/plugin-terser基本使用
在 Rollup 配置中引入
// rollup.config.js
import { terser } from '@rollup/plugin-terser';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.min.js',
format: 'esm'
},
plugins: [
terser() // 默认配置
]
};通常在其他转换插件(如 Babel)之后使用:
import babel from '@rollup/plugin-babel';
import { terser } from '@rollup/plugin-terser';
plugins: [
babel(), // 先转译
terser() // 后压缩
]关键配置选项:
| 选项 | 说明 |
|---|---|
format | 输出格式(默认继承 Rollup 的 output.format)。 |
mangle | 是否混淆变量名(默认 true)。 |
compress | 压缩配置(可禁用或细化规则)。 |
keep_classnames | 是否保留类名(默认 false,对依赖类名的库设为 true)。 |
keep_fnames | 是否保留函数名(默认 false,对依赖函数名的库设为 true)。 |
module | 是否输出 ES Module(默认 false,设为 true 可优化 Tree-Shaking)。 |
sourceMap | 是否生成 Sourcemap(默认 false,生产环境建议关闭)。 |
maxWorkers | 最大线程数(默认 4,提升多核 CPU 的压缩速度)。 |
示例:自定义配置
terser({
mangle: {
properties: true, // 混淆对象属性名
reserved: ["$", "exports"] // 保留特定名称
},
compress: {
drop_console: true, // 移除 console.log
dead_code: true // 移除死代码
},
keep_classnames: false,
format: {
comments: false // 移除注释
}
})性能优化建议
- 启用多线程压缩;通过
maxWorkers加速构建:
terser({
maxWorkers: 4 // 根据 CPU 核心数调整
})- 排除开发依赖;在开发构建中禁用压缩
// rollup.config.js
const isProduction = process.env.NODE_ENV === 'production';
export default {
plugins: [
isProduction && terser() // 仅生产环境启用
].filter(Boolean)
};- 避免过度压缩
某些库依赖特定的变量名或类名(如 React、Redux),需通过 reserved 保留:
terser({
mangle: {
reserved: ['React', 'Redux']
}
})常见问题与解决
- Sourcemap 错误
问题:压缩后 Sourcemap 不准确。
解决:确保 Rollup 的 output.sourcemap 和 terser 的 sourceMap 配置一致:
output: {
sourcemap: true // Rollup 生成 Sourcemap
},
plugins: [
terser({ sourceMap: true }) // Terser 生成压缩后的 Sourcemap
]- 变量名混淆导致运行时错误
问题:压缩后变量名被缩短,但某些代码依赖动态属性名(如 obj[key])
解决:禁用特定属性的混淆:
terser({
mangle: {
properties: {
regex: /^_/, // 不混淆以 _ 开头的属性
reserved: ['propName'] // 保留特定属性名
}
}
})- 压缩后代码体积未显著减少
原因:可能未启用 Tree-Shaking 或存在未优化的依赖。 检查步骤:
-
确认 Rollup 的
output.format为esm或cjs(iife/umd不易优化) -
使用
rollup-plugin-visualizer分析打包体积:bashnpm install --save-dev rollup-plugin-visualizer配置:
JavaScriptimport { visualizer } from 'rollup-plugin-visualizer'; plugins: [ visualizer() // 生成 stats.html ]
rollup-plugin-postcss
rollup-plugin-postcss 是 Rollup 生态中用于处理 CSS 的核心插件,它集成了 PostCSS 的强大功能,支持 CSS 预处理(Sass/Less)、模块化(CSS Modules)、自动前缀(Autoprefixer)、代码压缩 等特性,是现代前端项目打包 CSS 资源的首选工具
| 功能 | 说明 |
|---|---|
| CSS 预处理 | 支持 Sass、Less、Stylus 等编译为 CSS。 |
| CSS Modules | 局部作用域 CSS(生成哈希类名避免冲突)。 |
| Autoprefixer | 自动添加浏览器前缀(如 -webkit-)。 |
| CSS 压缩 | 通过 cssnano 移除空格和注释。 |
| CSS 代码拆分 | 支持生成独立的 .css 文件(而非内联 JS)。 |
| Sourcemap 生成 | 开发环境调试友好。 |
| Tree-Shaking | 结合 purgecss 移除未使用的 CSS。 |
需安装插件及常用配套工具:
# 基础安装
npm install -D rollup-plugin-postcss postcss
# 可选:预处理、Autoprefixer、CSS Modules
npm install -D sass autoprefixer cssnano postcss-modules
# 或使用 Less/Stylus
npm install -D less stylus基本使用
在 Rollup 中引入
// rollup.config.js
import postcss from 'rollup-plugin-postcss';
export default {
input: 'src/main.js',
output: { dir: 'dist', format: 'esm' },
plugins: [
postcss({
plugins: [], // PostCSS 插件(如 autoprefixer)
extract: true, // 提取为独立 CSS 文件
modules: true, // 启用 CSS Modules
sourceMap: true, // 开发环境启用 Sourcemap
})
]
};配合预处理语言(Sass/Less)
postcss({
plugins: [],
use: ['sass'], // 使用 Sass(需安装 sass)
extract: true
})关键配置选项:
| 选项 | 类型 | 说明 |
|---|---|---|
extract | boolean | 是否提取 CSS 为独立文件(默认 false,内联到 JS 中)。 |
modules | boolean | 启用 CSS Modules(默认 false)。 |
sourceMap | boolean | 生成 Sourcemap(默认 false)。 |
plugins | array | PostCSS 插件列表(如 [autoprefixer(), cssnano()])。 |
use | array | 预处理语言(如 ['sass', 'less'])。 |
inject | boolean | 将 CSS 注入 JS 并动态插入 <style> 标签(默认 false)。 |
minimize | boolean | 是否压缩 CSS(默认 production 环境为 true)。 |
config | boolean | 是否读取 postcss.config.js(默认 true)。 |
高级用法
- 使用 CSS Modules
// rollup.config.js
postcss({
modules: true,
generateScopedName: '[name]__[local]___[hash:base64:5]' // 自定义类名格式
})
// 在 JS 中引用
import styles from './styles.module.css';
console.log(styles.myClass); // 输出哈希类名(如 `_myClass_1f2j3`)- 自定义 PostCSS 插件
// postcss.config.js
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
export default {
plugins: [
autoprefixer({ overrideBrowserslist: '> 0.5%' }),
cssnano() // 生产环境压缩
]
};- 按需引入 CSS(Tree-Shaking);结合
purgecss移除未使用的 CSS:
import purgecss from '@fullhuman/postcss-purgecss';
postcss({
plugins: [
purgecss({
content: ['./src/**/*.html', './src/**/*.js'] // 扫描 HTML/JS 中的类名
})
]
})与其他插件的协作
- 与
@rollup/plugin-image配合处理 CSS 中的图片资源:
import image from '@rollup/plugin-image';
plugins: [
image(),
postcss()
]- 与
rollup-plugin-livereload配合开发环境实时刷新 CSS:
import livereload from 'rollup-plugin-livereload';
plugins: [
postcss({ extract: true }),
livereload({ watch: 'dist' }) // 监听 dist 目录变化
]rollup 按需加载
直接引用使用的组件即可,这样在 build 时不会将整个组件库打包
注意:需要 babel 支持,参考:https://element.eleme.cn/#/zh-CN/component/quickstart
rollup-plugin-vue
rollup-plugin-vue 是 Rollup 的官方插件,用于直接打包 Vue 单文件组件,支持 Vue 2 和 Vue 3 的模板、样式和逻辑代码的解析与优化
| 功能 | 说明 |
|---|---|
| Vue SFC 支持 | 解析 .vue 文件中的 <template>、<script> 和 <style> 块 |
| 模板编译 | 将 Vue 模板转换为渲染函数(支持 Vue 2 的 compiler 和 Vue 3 的 @vue/compiler-sfc) |
| CSS 处理 | 支持 <style> 块的预处理(Sass/Less)、作用域 CSS(Scoped CSS)和 CSS Modules |
| 热更新(HMR) | 开发环境下支持模块热替换 |
| Tree-Shaking | 结合 Rollup 移除未使用的代码 |
| Sourcemap 生成 | 支持调试编译后的代码 |
安装:
# Vue 2 项目
npm install --save-dev rollup-plugin-vue@5 vue-template-compiler
# Vue 3 项目
npm install --save-dev rollup-plugin-vue@6 @vue/compiler-sfc注意:
rollup-plugin-vue的 v5 对应 Vue 2,v6 对应 Vue 3,需匹配版本。
基本使用
Vue 2 配置示例
// rollup.config.js
import vue from 'rollup-plugin-vue';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
plugins: [
resolve(), // 解析 node_modules 依赖
commonjs(), // 转换 CommonJS 模块
vue({
css: true, // 提取 CSS 为独立文件
compileTemplate: true // 显式启用模板编译
})
]
};Vue 3 配置示例
import vue from 'rollup-plugin-vue';
import { nodeResolve } from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: { dir: 'dist', format: 'esm' },
plugins: [
nodeResolve(),
vue({
target: 'browser', // 指定目标环境(browser/node)
css: 'dist/vue-components.css' // 提取所有 CSS 到指定文件
})
]
};关键配置选项:
| 选项 | 说明 |
|---|---|
css | 控制 CSS 处理方式: - true:提取为独立文件。 - false:内联到 JS 中。 - 字符串:指定提取的 CSS 文件名。 |
compileTemplate | 是否编译模板(默认 true)。 |
target | 目标环境:'browser'(默认)或 'node'(SSR 场景)。 |
style | 配置 <style> 块的处理: - postcss:启用 PostCSS 插件。 - trim:移除空格。 |
preprocessStyles | 预处理 <style> 块(支持 Sass/Less)。 |
preprocessOptions | 预处理器的配置(如 Sass 的 includePaths)。 |
hmr | 是否启用热更新(默认开发环境为 true)。 |
customBlocks | 处理自定义块(如 <docs>)。 |
常见问题与解决
- 模板编译报错(Vue 2)
问题:Error: Cannot find module 'vue-template-compiler'。
解决:确保安装了 vue-template-compiler 且版本与 vue 一致:
npm install vue-template-compiler@2.6.14 --save-dev- 样式未提取为独立文件
问题:css: true 无效。
解决:确保 Rollup 的 output.dir(而非 output.file)已设置:
output: { dir: 'dist', format: 'esm' } // 必须为目录格式- Vue 3 的
<script setup>语法支持
问题:<script setup> 未被正确处理。
解决:确保使用 rollup-plugin-vue@6 并安装 @vue/compiler-sfc:
npm install @vue/compiler-sfc@3 --save-deeslint 配置
npm i -D eslint
# 执行 下面的命令后,会出现一个交互式的命令行
./node_modules/.bin/eslint --init
✔ What do you want to lint? · javascript, css
✔ How would you like to use ESLint? · syntax
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · vue
✔ Does your project use TypeScript? · no / yes
✔ Where does your code run? · browser
The config that you've selected requires the following dependencies:
eslint, globals, typescript-eslint, eslint-plugin-vue, @eslint/css
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm配置 eslint 脚本:
{
"lint": "eslint ./src"
}注:eslint 无需全局安装
本地使用
在组件库执行的命令
npm link使用组件库的项目,手动在 package.json 中指定模块名和版本号
npm link 模块名npm 发布
npm login
npm publish如果使用 @group/npmName 这种发布时,请注意是否有 @group 发布权限,如果没有,可以创建 @group 后再发布,建议个人用户不要用 @group/npmName 这种格式