webpack之外的打包工具(Rollup,Parcel)
我们接触最多的可能是webpack,但现在其实还有很多其他的打包工具,所以在此文章做一个整理,让我们有更多的角度去认识打包工具的发展,也有助于未来工程的技术选型。
此文章主要讲:
- Rollup和Parcel各自的特点和优势
- JavaScript打包工具发展的趋势
- 如何选择合适的打包工具
Rollup
如何用Webpack和Rollup进行比较的话
- webpack的优势在于他更加全面,基于”一切皆模块“的思想而衍生出丰富的loader和plugin可以满足各种使用场景
- Rollup更像一把手术刀,它更专注于JavaScript的打包。
- 当然也支持其他类型的模块,但总体而言在通用性上还是不如webpack。如果当前的项目需求仅仅是打包JavaScript,比如一个JavaScript库,那么Rollup很多时候会是我们的第一选择。
配置
简单示例看看Rollup如何工作
首先创建rollup.config.js以及我们打包的项目文件app.js
// rollup.config.js
module.exports = {
input: 'src/app.js',
output: {
file: 'dist/bundle.js',
format: 'cjs' // CommonJS
}
}
// app.js
console.log(123)
与webpack一般装在项目内部不同,rollup直接全局安装即可
(sudo) npm i rollup -g
然后使用rollup命令打包
rollup -c rollup.config.js
- -c参数是告诉Rollup使用该配置文件。
打包结果如下:(非常干净)
'use strict'
console.log(123)
使用webpack的话,大概有50行左右(webpack自身代码注入)。显然rollup打包出来的体积要小,不包含无关代码
tree shaking
虽然webpack也有,但最早开始于rollup,后面被webpack所借鉴
- (类似的还有,输出格式)在webpack的早期,Rollup有一项webpack不具有的功能:通过配置output.format开发者可以选择输出资源的模块形式(cjs(CommonJS),esm(ES6 Modules),amd,umd,iife,system等),此特性对于打包JavaScript库特别有用,因为往往一个库需要支持多种不同的模块形式,而通过rollup几个命令就可以把一份源代码打包为多份
rollup的tree shaking也是基于ES6 Mudules 的静态分析,找出没有被引用过的模块,将其从最后生成的bundle中去除。
举个例子
// app.js
import { add } from './util.js'
console.log(add(2, 3))
// util.js
export function add(a, b) {
return a + b
}
export function sub(a, b) {
return a - b
}
Rollup的打包结果如下:
'use strict'
function add(a, b) {
return a + b
}
console.log(add(2, 3))
可以看到util.js中的sub函数没有被引用过,因此也没有出现在最终的bundle.js中。与之前一样,输出的内容非常清晰简洁,没有附加代码
实际应用
在实际应用中,rollup经常被用于打包一些库或框架(vue,react)
react团队在一篇博文中提到,他们将react原有的打包工具从Browserify迁移到rollup,获得了以下几项收益:
- 最低限度的附加代码
- 对ES6 Modules的良好支持
- 通过 tree shaking去除开发环境代码
- 通过自定义插件在实现一些react特性化的打包逻辑
Rollup没有webpack对于应用开发那样强大的支持(支持各种loader和plugin,HMR等),因为他设计之初,就是主要偏向于JavaScript库的构建
总结:Rollup更像一把手术刀,它更专注于JavaScript的打包。
- 当然也支持其他类型的模块,但总体而言在通用性上还是不如webpack。如果当前的项目需求仅仅是打包JavaScript,比如一个JavaScript库,那么Rollup很多时候会是我们的第一选择。
Parcel
Parcel在js打包工具中属于相对后来者(根据npm版本上传显示最早上传于 2017.8,webpack是2021.3,rollup是2015.5)
打包速度
在Parcel官网的Benchmark测试中,在有缓存的情况下其打包速度比webpack快近8倍,且宣称自己是零配置。他的出现正好契合当时开发者们对于webpack打包慢和配置复杂的抱怨,从而吸引了很多用户
Parcel在打包速度上主要做了3件事情:
- 利用worker来并行执行任务
- 文件系统缓存
- 资源编译处理流程优化
上面3点的前两个webpack已经在做了。比如webpack在资源压缩时可用利用多核同时压缩多个资源(但资源编译过程中还没实现);本地缓存则更多的是在loader层面,像babel-loader就会把编译结果缓存在项目中的一个隐藏目录里,并通过本地文件的修改时间和状态来判断是否使用上次编译的缓存。第三点是Parcel最大的优势:因为webpack的每个loader都要生成一遍AST,Parcel则不用,只需生成一次AST(相当于Parcel内置了loader,才能做此优化)
零配置
非常方便和快速
具体操作可以参考官网:https://www.parceljs.cn/getting_started.html
总结:Parcel相比于webpack来说,优势在于快速和灵巧。假如我们需要在很短的时间内搭建一个原型,或者不需要进行深度定制的工程,那么使用Parcel的话前期开发速度会很快。
- 以前即便做一个小工程使用Webpack也要先写一堆配置,现在我们多了另外一种选择
打包工具的发展趋势
- 性能与通用性
- 打包速度趋向越来越快,但越通用就必须会牺牲掉一些性能。如Parcel对比webpack,Parcel牺牲的通用性去提升打包性能
- 配置极小化与工程标准化
- 极小化配置甚至零配置逐渐成为一个重要的特性。Parcel让大家知道,打包工具并不一定非要写一大堆配置,很多东西可以被简化。Parcel出现不久后,webpack也在4.0的版本中宣称自己是零配置
- 极小化配置的背后体现出来的就是js工程的标准化。最简单的就是源码目录(比如src)和产出资源目录(比如dist)。成为默认项之后,对整个社区的发展是一件好事
- WebAssembly
- 未来说不定通过loader就能加载c代码模块
参考《Webpack实战:入门、进阶与调优》(居玉皓)