webpack 对前端来说是再熟悉不过的工具了,它提供了强大的功能来构建前端的资源,包括 html/js/ts/css/less/scss ...
等语言脚本,也包括 images/fonts ...
等二进制文件。
其实,webpack 发起之初主要是为了解决以下两个问题:
- 代码拆分(Code Splitting): 可以将应用程序分解成可管理的代码块,可以按需加载,这样用户便可快速与应用交互,而不必等到整个应用程序下载和解析完成才能使用,以此构建复杂的单页应用程序(SPA);
- 静态资源(Static Assets): 可以将所有的静态资源,如 js、css、图片、字体等,导入到应用程序中,然后由 webpack 使用 hash 重命名需要的资源文件,而无需为文件 URL 增添 hash 而使用 hack 脚本,并且一个资源还能依赖其他资源。
正是因为 webpack 拥有如此强大的功能,所以 webpack 在进行资源打包的时候,就会产生很多冗余的代码(如果你有查看过 webpack 的 bundle 文件,便会发现)。
比如,把 export default str => str;
这段代码用 webpack 打包就会得到下面的结果:
1 | /******/ (function(modules) { // webpackBootstrap |
这在以下的一些情境中就不太高效,需要寻求更好的解决方案:
- 需要 js 高效运行。因为 webpack 对子模块定义和运行时的依赖处理(
__webpack_require__
),不仅导致文件体积增大,还会大幅拉低性能; - 项目(特别是类库)只有 js,而没有其他的静态资源文件,使用 webpack 就有点大才小用了,因为 webpack bundle 文件的体积略大,运行略慢,可读性略低。
在这种情况下,就想要寻求一种更好的解决方案,这便是 rollup.
现在已经有很多类库都在使用 rollup 进行打包了,比如:react, vue, preact, three.js, moment, d3 等。
1. 工具
安装
1 | npm i -g rollup # 全局安装 |
使用
1 | rollup -c # 使用一个配置文件,进行打包操作 |
更多详细的用法,参考 rollup.js - command-line-flags.
2. 配置
rollup 的配置与 webpack 的配置类似,定义在 rollup.config.js
文件中,比如:
1 | // rollup.config.js |
常用的几个配置项:
input
: 源码入口文件,一般是一个文件,如src/index.js
。output
: 定义输出,如文件名,目标目录,输出模块范式(es6
,commonjs
,amd
,umd
,iife
等),模块导出名称,外部库声明,全局变量等。plugins
: 插件,比如 rollup-plugin-json 可以让 rollup 从.json
文件中导入 json 数据。
更多详细的配置,参考 rollup.js - configuration-files.
3. rollup 与 webpack 对比
先拿段代码来来看看他们打包之后各自是什么效果。
源代码
1 | # 目录 |
配置
1 | # webpack.config.js |
运行
1 | # webpack 打包 |
webpack.bundle.js
1 | (function webpackUniversalModuleDefinition(root, factory) { |
rollup.bundle.js
1 | (function (global, factory) { |
其实,你也基本上看出来了,在这种场景下,rollup 的优势在哪里:
- 文件很小,几乎没什么多余代码,除了必要的
cjs
,umd
头外,bundle 代码基本和源码差不多,也没有奇怪的__webpack_require__
,Object.defineProperty
之类的东西; - 执行很快,因为没有 webpack bundle 中的
__webpack_require__
,Object.defineProperty
之类的冗余代码; - 另外,rollup 也对 es 模块输出及 iife 格式打包有很好的支持。
4. 结论
rollup 相对 webpack 而言,要小巧、干净利落一些,但不具备 webpack 的一些强大的功能,如热更新,代码分割,公共依赖提取等。
所以,一个不错的选择是,应用使用 webpack,类库使用 rollup。