blog
blog copied to clipboard
Rollup 打包入门
前言
官方文档
- https://rollupjs.org/guide/en/
- https://rollupjs.org/guide/zh/
rollup 对比 webpack
共同点:
- 通过插件生态的方式处理各种各样的资源依赖
不同点:
- webpack 致力于复杂 SPA 的模块化构建, rollup 致力于打造性能出众的类库;
- rollup 打包后生成的 bundle 内容十分干净,没有什么多余的代码。相比 webpack(webpack 打包后会生成 webpack_require 等 runtime 代码),rollup 拥有无可比拟的性能优势,这是由依赖处理方式决定的,编译时依赖处理(rollup)自然比运行时依赖处理(webpack)性能更好;
- 对于 ES 模块依赖库,rollup 会静态分析代码中的 import,并将排除任何未实际使用的代码(tree-shaking)
- rollup 支持导出 es 模块文件(webpack 不支持导出 es 模块)
- webpack 支持提取公共模块
快速入门
- 创建简单项目
mkdir -p my-rollup-project/src
cd my-rollup-project
首先,我们需要个 入口。将以下代码粘贴到新建的文件 src/main.js 中:
// src/main.js
import foo from "./foo.js";
export default function () {
console.log(foo);
}
之后创建入口文件引用的 foo.js 模块:
// src/foo.js
export default "hello world!";
- 安装 rollup
npm init -y
yarn add rollup -D
- 创建 rollup.config.js
export default {
input: "src/main.js", // 要打包的文件源路径
output: {
// 文件输出配置
file: "dist/bundle.js", // 打包后生产的文件位置及文件名
format: "iife", // 输出的文件类型 (amd, cjs, esm, iife, umd)
name: "bundleName", // 包的全局变量名称
},
};
- 编写 package.json 中的打包命令
{
"scripts": {
"build": "rollup --config rollup.config.js"
}
}
- 执行
npm run build
查看文件输出结果
var bundleName = (function () {
"use strict";
var foo = "hello world!";
function main() {
console.log(foo);
}
return main;
})();
核心配置
// 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/main.js", //填写打包的入口文件路径
output: {
file: "dist/bundle.js", // 打包后生产的文件位置及文件名
format: "iife", // 输出的文件类型 (amd, cjs, esm, iife, umd)
name: "bundleName", //当format为iife和umd时必须提供,将作为全局变量挂在window(浏览器环境)下:window.bundleName=...
globals: {
lodash: "_",
},
},
external: ["lodash"], //告诉rollup不要将此lodash打包,而作为外部依赖
plugins: [
resolve(),
commonjs(),
babel({
exclude: "node_modules/**",
}),
],
};
- 打包格式说明
生成包的格式。 下列之一:
- amd – 异步模块定义,用于像 RequireJS 这样的模块加载器
- cjs – CommonJS,适用于 Node 和 Browserify/Webpack
- esm – 将软件包保存为 ES 模块文件,在现代浏览器中可以通过
<script type=module>
标签引入 - iife – 一个自动执行的功能,适合作为
<script>
标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。) - umd – 通用模块定义,以 amd,cjs 和 iife 为一体
- system - SystemJS 加载器格式
- external + output.globals
rollup 通过external
+ output.globals
来标记外部依赖,以 react-redux
开源项目的 rollup 配置文件为例:
import nodeResolve from "rollup-plugin-node-resolve"; // 帮助寻找node_modules里的包
import babel from "rollup-plugin-babel"; // rollup 的 babel 插件,ES6转ES5
import replace from "rollup-plugin-replace"; // 替换待打包文件里的一些变量,如process在浏览器端是不存在的,需要被替换
import commonjs from "rollup-plugin-commonjs"; // 将非ES6语法的包转为ES6可用
import uglify from "rollup-plugin-uglify"; // 压缩包
const env = process.env.NODE_ENV;
const config = {
input: "src/index.js",
external: ["react", "redux"], // 告诉rollup,不打包react,redux;将其视为外部依赖
output: {
format: "umd", // 输出 UMD格式,各种模块规范通用
name: "ReactRedux", // 打包后的全局变量,如浏览器端 window.ReactRedux
globals: {
react: "React", // 这跟external 是配套使用的,指明global.React即是外部依赖react
redux: "Redux",
},
},
plugins: [
nodeResolve(),
babel({
exclude: "**/node_modules/**",
}),
replace({
"process.env.NODE_ENV": JSON.stringify(env),
}),
commonjs(),
],
};
if (env === "production") {
config.plugins.push(
uglify({
compress: {
pure_getters: true,
unsafe: true,
unsafe_comps: true,
warnings: false,
},
})
);
}
export default config;
- 常用插件
- @rollup/plugin-node-resolve 解析 node_modules 中的模块
- @rollup/plugin-commonjs 转换 CJS -> ESM, 通常配合上面一个插件使用
- rollup-plugin-babel 打包过程中使用 Babel 进行转换, 需要安装和配置 Babel(
.babelrc
) - @rollup/plugin-replace 类似于 webpack 的 DefinePlugin
- @rollup/plugin-alias 配置 module 的别名
- rollup-plugin-terser 适用于 ES6 +的 JavaScript 代码压缩
- 文件导入
- rollup-plugin-json 编译 json
- rollup-plugin-postcss/postcss 编译 css
- rollup-plugin-scss
- autoprefixer
- postcss-pxtorem
- cssnano 压缩 css
- @rollup/plugin-url
- rollup-plugin-vue
- 开发调试
- rollup-plugin-serve 开启本地服务器
- rollup-plugin-livereload 开启热更新
附插件配置案例:
{
"scripts": {
"rollup:dev": "cross-env NODE_ENV=development rollup --config ./rollup/rollup.config.js -w",
"rollup:build": "cross-env NODE_ENV=production rollup --config ./rollup/rollup.config.js"
}
}
import babel from "rollup-plugin-babel";
import node from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import replace from "@rollup/plugin-replace";
import json from "rollup-plugin-json";
import { terser } from "rollup-plugin-terser";
import alias from "@rollup/plugin-alias";
import postcss from "rollup-plugin-postcss";
import serve from "rollup-plugin-serve";
import livereload from "rollup-plugin-livereload";
import { version } from "../package.json";
const path = require("path");
const resolve = (p) => path.resolve(__dirname, p);
const env = process.env.NODE_ENV;
const config = {
input: "./rollup/src/main.js",
output: {
file: "./dist/bundle.js",
format: "iife", //输出格式 amd es6 iife umd cjs
// window.MyBundle.exportFunctionName
name: "MyBundle", //当format为iife和umd时必须提供,将作为全局变量挂在window(浏览器环境)下:window.A=...
banner: "/* my-library version " + version + " */",
intro: 'var ENVIRONMENT = "production";',
sourcemap: true, // 生成 bundle.map.js文件,方便调试
},
plugins: [
node(),
babel({
exclude: "node_modules/**", // 只编译我们的源代码
}),
json(),
postcss(),
alias({
entries: {
"@": resolve("src"),
"~": resolve("../"),
},
customResolver: node({
extensions: [".vue", ".js", ".scss"],
}),
}),
replace({
"process.env.NODE_ENV": JSON.stringify(env),
}),
commonjs(),
// 热更新与开启本地服务器
livereload(),
serve({
open: true,
port: 8001,
contentBase: "dist",
}),
],
global: {
lodash: "_", //告诉rollup全局变量
},
external: ["lodash"], // 不参与打包,使用外部引用
};
if (env !== "production") {
config.plugins.push(
terser({
compress: {
pure_getters: true,
unsafe: true,
unsafe_comps: true,
warnings: false,
},
})
);
}
export default config;
完整配置项
https://rollupjs.org/guide/zh/#big-list-of-options
// rollup.config.js
export default {
// 核心选项
input, // 必须
external,
plugins,
// 额外选项
onwarn,
// danger zone
acorn,
context,
moduleContext,
legacy
output: { // 必须 (如果要输出多个,可以是一个数组)
// 核心选项
file, // 必须
format, // 必须
name,
globals,
// 额外选项
paths,
banner,
footer,
intro,
outro,
sourcemap,
sourcemapFile,
interop,
// 高危选项
exports,
amd,
indent
strict
},
};