为什么说rollup比webpack更适合打包库
前言
大概一年前写了个小小的js插件 remember-scroll
,并且分享了一篇文章: 用Class写一个记住用户离开位置的js插件
,是一个纯js库,功能是在用户再次进入页面时能自动定位到上一次浏览的位置,使用webpack+babel打包,里面的webpack和babel的配置至今看来也算是很典型的。
前端打包工具有很多—— webpack
, gulp
, rollup
等等,网上有很多文章分析它们分别更适合哪些场景,
webpack
更适合打包组件库、应用程序之类的应用,而 rollup
更适合打包纯js的类库
。因此笔者一直有想法尝试将 remember-scroll
的打包工具由 webpack
更换为 rollup
,从实际应用的角度来对比一下两者的区别。
从零配置rollup
- 安装rollup和一些插件
npm i rollup rollup-plugin-uglify rollup-plugin-filesize @rollup/plugin-node-resolve @rollup/plugin-commonjs -D
-
rollup-plugin-uglify
用于压缩混淆打包后的js。 -
rollup-plugin-filesize
打包后在控制台显示文件大小。 -
@rollup/plugin-node-resolve
让rollup
能够识别node_modules的第三方模块。 -
@rollup/plugin-commonjs
将 CommonJS 的模块转换为 ES2015 供rollup
处理。
- 添加babel
npm i @rollup/plugin-babel @babel/core @babel/plugin-transform-runtime @babel/preset-env core-js@2 -D
@rollup/plugin-babel @babel/core @babel/plugin-transform-runtime @babel/preset-env core-js
根目录下的 babel.config.js
如下:
const presets = [ [ '@babel/env', { useBuiltIns: 'usage', corejs: { version: 2 } }, ], ] const plugins = [ '@babel/plugin-transform-runtime' ] module.exports = { presets, plugins }
-
根目录下新建
rollup.config.js
,全部配置如下:
import filesize from 'rollup-plugin-filesize' import babel from '@rollup/plugin-babel' import resolve from '@rollup/plugin-node-resolve' import { uglify } from 'rollup-plugin-uglify' import commonjs from '@rollup/plugin-commonjs' const isProd = process.env.NODE_ENV === 'production' export default { input: 'src/index.js', output: { file: isProd ? 'dist/remember-scroll.min.js' : 'dist/remember-scroll.js', format: 'umd', exports: 'default', name: 'RememberScroll', }, plugins: [ resolve(), commonjs(), filesize(), babel({ babelHelpers: 'runtime', exclude: ['node_modules/**'] }), (isProd && uglify()) ] }
-
package.json
打包命令如下:
"build": "rollup -c --environment NODE_ENV:production && rollup -c", "dev": "rollup -c --watch",
总之,一切配置都是与之前 webpack
版本的一样,都使用了babel。 npm run build
就可以将资源打包到dist了,接下来我们对比一下 webpack
和 rollup
两个工具打出来的体积有啥区别。
webpack和rollup打包体积对比
笔者特地建了一个同时有rollup和webpack打包出来的资源的分支,大家可以直接看下github上 feature/webpack_rollup
分支的 remember-scroll/dist
,对比结果如下:
– | webpack | rollup |
---|---|---|
开发模式大小 | 52.8KB | 19.46KB |
生产打包大小 | 10.3KB | 7.66KB |
生产包gzip后大小 | 4.1KB | 3.4KB |
可见, rollup
打包出来的体积都比 webpack
略小一些,通过查看打包出来的代码,webpack打包出来的文件里面有很多 __webpack_require__
工具函数的定义,可读性也很差,而rollup打包出来的js会简单一点。
项目的 master
分支已经改为使用rollup进行构建, feature/webpack
分支保留了之前webpack的配置,感兴趣的同学可以去github上详细了解下。
不得不说,从打包体积上来看,使用 rollup
构建无疑是更适合的。
package.json的main指向问题
笔者之前遇到过一个问题是 package.json
的 main
到底应该是指向构建后的开发版本还是生产版本呢?
关于package.json中main字段的指向问题
这篇文章给了答案: main应该指向开发版本。
这里会有一个疑问:引用开发版本的包体积很大,岂不是让我的应用打包上线版本很大?
为了验证上面 package.json 的 main
指向开发或生产版本有什么不同,笔者这里直接实战做个对比。
使用VueCli v4.5.9 新建一个vue项目,然后在 App.vue
引入不同工具打包而成的 remember-scroll
,再 npm run build
打包该vue项目,对比打包出来 chunk-vendors.[hash].js
的体积。
引入的npm包默认会打包进 chunk-vendors
, app.js
的增量体积都是一样的就不作对比了。
– | vue打包 | 引webpack开发版(52.8KB) | 引webpack生产版(10.3KB) | 引rollup开发版(19.46KB,推荐) | 引rollup生产版(7.66KB) |
---|---|---|---|---|---|
Size | 89.42KB | 134.97 | 99.34 | 97.29KB | 96.96KB |
Gzip | 32.04KB | 40.47 | 34.60 | 34.52KB | 34.51KB |
可以看到,使用 rollup
打包的,无论main指向开发版还是生产版,gzip后几乎一致,但 webpack
打包出来的,main指向开发版时体积会相差非常大。
所以使用 webpack
打包的插件,一般都是会根据 NODE_ENV
来加载对应的包, NODE_ENV === 'production'
时指向压缩后的生产版本。比如像下面这样,在根目录新建一个 index.js
, package.json
的 main
指向该文件,然后在js中写上:
if (process.env.NODE_ENV === 'production') { module.exports = require('./dist/remember-scroll.min.js') } else { module.exports = require('./dist/remember-scroll.js') }
倘若各位以后要写一个用webpack打包的插件,要特别注意这一点。
而如果用rollup打包的,其实就不用在意这个细节啦,在这个环节 rollup
又比 webpack
更香一点哈哈哈。
总结
通过实战,功能不变且浏览器兼容性一致的情况下,对 remember-scroll
这个js库来说,使用 rollup
打包确实比 webpack
会更合适一些。所以如果我们以后要做技术选型,对于纯js的类库,选择使用 rollup
会更合适一点。
当然, rollup
和 webpack
都是作为构建工具,它们都有着各自的优势和各自的使用场景,利用好它们的优点就可以了。
「一键投喂 软糖/蛋糕/布丁/牛奶/冰阔乐!」