Rollup 简介
rollup.js 是 JavaScript 的 ES 模块打包器,允许使用现代ES模块系统,将其转换为CommonJS、AMD或UMD,以及包装在IIFE中。更适用于js类库的打包。
默认采用 ES 模块标准,可以使用 rollup-plugin-commonjs 插件来支持 Commonjs 标准。
常见配置选项
- input: 入口文件
- output.file: 输出文件
- output.name: 生成包名称
- output.format
类型 说明 amd AMD模块,用于像 require.js 这样的模块加载器 cjs Commonjs,适用于 Node 和 Browserify、Webpack es ES 模块 iife 包装成IIFE, 具有自执行功能,适合script标签引用 umd amd,cjs 和 iife 一体
支持Tree-sharking
Rollup可以静态分析代码,并删除未使用的函数或模块。
- person.js
const members = ['张三', '李四', '王五'] const kids = ['小明', '小红', '小亮'] const getRandom = (start, end) => Math.floor(Math.random() * end) + start const getMember = () => members[getRandom(0, members.length - 1)] const getKid = () => kids[getRandom(0, kids.length - 1)] export { members, kids, getMember, getKid }
- main.js
import * as Person from './person' const getName = () => console.log(`My name is ${Person.getMember()}`) export default getName
打包后,
'use strict'; const members = ['张三', '李四', '王五']; const getRandom = (start, end) => Math.floor(Math.random() * end) + start; const getMember = () => members[getRandom(0, members.length - 1)]; const getName = () => console.log(`My name is ${getMember()}`); module.exports = getName;
解析第三方库
经常需要引入第三方库,如lodash-es
使用lodash-es取代person.js中getRandom方法。打包后的代码只是require('lodash-es'),并没有将lodash-es库打包到最终的代码中。
- person.js
import { random } from 'lodash-es' const members = ['张三', '李四', '王五'] const kids = ['小明', '小红', '小亮'] const getMember = () => members[random(0, members.length - 1)] const getKid = () => kids[random(0, kids.length - 1)] export default { members, kids, getMember, getKid }
rollup-plugin-node-resolve使用Nodejs节点分辨率算法定位modules,以便使用第三方模块node_modules。
npm i -D rollup-plugin-node-resolve
- rollup.config.js
import pkg from './package.json' import resolve from 'rollup-plugin-node-resolve' export default { input: 'src/main.js', output: [ { file: pkg.main, format: 'cjs' }, { file: pkg.module, format: 'es' }, { file: pkg.browser, format: 'umd', name: 'ModuleName' } ], plugins: [ resolve() ] }
解析CommonJS模块
lodash-es采用了es模块,但npm上还有很多不支持es模块的包。比如使用将lodash-es改成lodash
- person.js
import random from 'lodash/random'
const members = ['张三', '李四', '王五']
const kids = ['小明', '小红', '小亮']
const getMember = () => members[random(0, members.length - 1)]
const getKid = () => kids[random(0, kids.length - 1)]
export default { members, kids, getMember, getKid }
rollup -c,发现Rollup无法解析CommonJS格式。这时,需要借助rollup-plugin-commonjs
rollup-plugin-commonjs需要放在其他模块转换插件之前执行。
- rollup.config.js
import commonjs from 'rollup-plugin-commonjs' export default { plugins: [commonjs()] }
external
有时为了方便浏览器缓存,采用CDN引入第三方包。为避免再将其打包进文件,使用external排除其被打包。
export default { external: ['lodash/random] };
打包后生成的iife代码如下:
var ModuleName = (function (random) { 'use strict'; random = random && random.hasOwnProperty('default') ? random['default'] : random; const members = ['张三', '李四', '王五']; const kids = ['小明', '小红', '小亮']; // const getRandom = (start, end) => Math.floor(Math.random() * end) + start const getMember = () => members[random(0, members.length - 1)]; const getKid = () => kids[random(0, kids.length - 1)]; var Person = { members, kids, getMember, getKid }; const getName = () => console.log(`My name is ${Person.getMember()}`); return getName; }(random));
形参中变量random是无法找到的,需要跟cdn引入的lodash库全局变量保持一致。因此,这种情况下导出umd和iife格式需要配置全局变量键值映射。
- rollup.config.js
export default { output: [ { file: pkg.browser, format: 'umd', name: 'ModuleName', globals: { 'lodash/random': '_.random' } }, { file: 'dist/index.iife.js', format: 'iife', name: 'ModuleName', globals: { 'lodash/random': '_.random' } } ], external: [ 'lodash/random', ...Object.keys(pkg.dependencies), ...Object.keys(pkg.peerDependencies) ] }
同理,output配置项中name表示的是当前库的全局变量名。
rollup-plugin-json: 转换 json
npm i -D rollup-plugin-json
import json from "rollup-plugin-json"; export default { plugins: [ json() ] };
编译js
- rollup-plugin-babel:使用Babel编译ES 2015+代码
使用rollup-plugin-babel将您的ES 2015+代码转换为向后兼容的JavaScript版本
npm i -D @babel/core @babel/preset-env rollup-plugin-babel babel-plugin-external-helpers
@babel/preset-env可以轻松地定位最小运行环境,不需要手动选择插件。{useBuiltIns: 'usage'} 仅为已使用的功能导入polyfill。
rollup.config.js:
import babel from 'rollup-plugin-babel' export default { plugins: [ babel({ babelrc: false, presets: [['@babel/preset-env', { modules: false }]], include: ['src/**'], exclude: ['node_modules/**'], // 避免转译第三方脚本 // plugins: ['external-helpers', 'babel-plugin-transform-object-rest-spread'], runtimeHelpers: true, // 用来开启transform-runtme comments: false // 删除注释 }) ] }
- rollup-plugin-buble:显示bundle文件大小
将 ES6+代码编译成 ES2015 标准。配合rollup-plugin-async来支持async/await。
npm i -D rollup-plugin-buble
import buble from 'rollup-plugin-buble' export default { plugins: [ buble({ objectAssign: 'Object.assign', exclude: ['node_modules/**'] }) ] }
rollup-plugin-postcss:处理样式
- 处理 css
npm i -D rollup-plugin-postcss postcss-simple-vars postcss-nested postcss-cssnext cssnano
import postcss from 'rollup-plugin-postcss'
import simplevars from 'postcss-simple-vars'
import nested from 'postcss-nested'
import cssnext from 'postcss-cssnext'
import cssnano from 'cssnano'
export default {
plugins: [
postcss({
plugins: [
simplevars(),
nested(),
cssnext({ warnForDuplicates: false }),
cssnano()
],
extensions: ['.css']
})
]
}
- 处理 scss
npm i -D rollup-plugin-postcss postcss-scss autoprefixer postcss-base64
import postcss from 'rollup-plugin-postcss'
import scss from 'postcss-scss'
import autoprefixer from 'autoprefixer'
import base64 from 'postcss-base64'
export default {
plugins: [
postcss({
extract: true,
parser: scss,
plugins: [
base64({
extensions: ['.png', '.jpeg'],
root: './packages/',
}),
autoprefixer({ add: true }),
]
})
]
}
rollup-plugin-url:处理图片
npm i -D rollup-plugin-url
import url from "rollup-plugin-url"
export default {
entry: 'src/main.js',
dest: 'dist/bundle.js',
sourcemaps: true,
plugins: [
url({
limit: 10 * 1024,
include: ["**/*.svg"],
emitFiles: true
})
]
}
rollup-plugin-vue2:处理 vue
npm i -D rollup-plugin-vue2 rollup-plugin-css-only
import vue from 'rollup-plugin-vue2'
import css from 'rollup-plugin-css-only'
export default {
entry: 'src/main.js',
dest: 'dist/bundle.js',
sourcemaps: true,
plugins: [
vue({
compileTemplate: true,
htmlMinifier: {
customAttrSurround: [[/@/, new RegExp('')], [/:/, new RegExp('')]],
collapseWhitespace: true,
removeComments: true
}
}),
css()
]
}
rollup-plugin-alias:提供别名
npm i -D rollup-plugin-alias
import alias from 'rollup-plugin-alias'
export default {
plugins: [
alias({
vue: 'vue/dist/vue.esm.js'
})
]
}
rollup-plugin-replace:设置环境变量
npm i -D rollup-plugin-replace
import replace from 'rollup-plugin-replace'
const ENV = process.env.NODE_ENV
export default {
plugins: [
replace({
exclude: 'node_modules/**',
'process.env.NODE_ENV': JSON.stringify(ENV),
ENV: JSON.stringify('development')
})
]
}
压缩
uglify 插件不支持 ES 模块和 es6 语法,主要用来打包 es5 语法
npm i -D rollup-plugin-uglify
import { uglify } from "rollup-plugin-uglify";
export default {
plugins: [
uglify()
]
};
npm i -D rollup-plugin-terser
import {terser} from 'rollup-plugin-terser' export default { plugins: [ terser({ output: { ascii_only: true // 仅输出ascii字符 }, compress: { pure_funcs: ['console.log'] // 去掉console.log函数 } }) ] };
rollup-plugin-cpy
npm i -D rollup-plugin-cpy
import copy from 'rollup-plugin-cpy' export default { plugins: [ copy({ files: ['src/*.png', '!src/goat.png'], dest: 'dist', options: { verbose: true } }) ] }
rollup-plugin-typescript2
npm i -D rollup-plugin-typescript2 typescript
- rollup.config.js
import typescript from 'rollup-plugin-typescript2' export default { plugins: [ typescript({ typescript: require('typescript') }) ] }
- package.json
{ "scripts": { "build": "rollup -c && tsc", "build:watch": "rollup -cw", } }
rollup-plugin-filesize
npm i -D rollup-plugin-filesize
import filesize from 'rollup-plugin-filesize' export default { plugins: [ filesize() ] }
rollup-plugin-istanbul
npm i -D rollup-plugin-istanbul
import istanbul from 'rollup-plugin-istanbul';
rollup-plugin-serve
npm install -D rollup-plugin-serve
rollup-watch
npm i -D rollup-watch livereload npm-run-all
- package.json
"scripts": {
"prebuild": "rimraf dist",
"build": "rollup -c",
"build:watch": "rollup -cw",
"prepublishOnly": "npm run build"
"reload": "livereload 'build/'",
"watch": "npm-run-all --parallel reload build:watch"
},