webpack之外的打包工具(Rollup,Parcel)

我们接触最多的可能是webpack,但现在其实还有很多其他的打包工具,所以在此文章做一个整理,让我们有更多的角度去认识打包工具的发展,也有助于未来工程的技术选型。

此文章主要讲:

  1. Rollup和Parcel各自的特点和优势
  2. JavaScript打包工具发展的趋势
  3. 如何选择合适的打包工具

Rollup

如何用Webpack和Rollup进行比较的话

  • webpack的优势在于他更加全面,基于”一切皆模块“的思想而衍生出丰富的loader和plugin可以满足各种使用场景
  • Rollup更像一把手术刀,它更专注于JavaScript的打包。
    • 当然也支持其他类型的模块,但总体而言在通用性上还是不如webpack。如果当前的项目需求仅仅是打包JavaScript,比如一个JavaScript库,那么Rollup很多时候会是我们的第一选择。

配置

简单示例看看Rollup如何工作

首先创建rollup.config.js以及我们打包的项目文件app.js

  1. // rollup.config.js
  2. module.exports = {
  3. input: 'src/app.js',
  4. output: {
  5. file: 'dist/bundle.js',
  6. format: 'cjs' // CommonJS
  7. }
  8. }
  9. // app.js
  10. console.log(123)

与webpack一般装在项目内部不同,rollup直接全局安装即可

(sudo) npm i rollup -g

然后使用rollup命令打包

rollup -c rollup.config.js

  • -c参数是告诉Rollup使用该配置文件。

打包结果如下:(非常干净)

  1. 'use strict'
  2. 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中去除。

举个例子

  1. // app.js
  2. import { add } from './util.js'
  3. console.log(add(2, 3))
  4. // util.js
  5. export function add(a, b) {
  6. return a + b
  7. }
  8. export function sub(a, b) {
  9. return a - b
  10. }

Rollup的打包结果如下:

  1. 'use strict'
  2. function add(a, b) {
  3. return a + b
  4. }
  5. console.log(add(2, 3))

可以看到util.js中的sub函数没有被引用过,因此也没有出现在最终的bundle.js中。与之前一样,输出的内容非常清晰简洁,没有附加代码

实际应用

在实际应用中,rollup经常被用于打包一些库或框架(vue,react)

  • react团队在一篇博文中提到,他们将react原有的打包工具从Browserify迁移到rollup,获得了以下几项收益:

    1. 最低限度的附加代码
    2. 对ES6 Modules的良好支持
    3. 通过 tree shaking去除开发环境代码
    4. 通过自定义插件在实现一些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件事情:

  1. 利用worker来并行执行任务
  2. 文件系统缓存
  3. 资源编译处理流程优化

上面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也要先写一堆配置,现在我们多了另外一种选择

打包工具的发展趋势

  1. 性能与通用性
    • 打包速度趋向越来越快,但越通用就必须会牺牲掉一些性能。如Parcel对比webpack,Parcel牺牲的通用性去提升打包性能
  1. 配置极小化与工程标准化
    • 极小化配置甚至零配置逐渐成为一个重要的特性。Parcel让大家知道,打包工具并不一定非要写一大堆配置,很多东西可以被简化。Parcel出现不久后,webpack也在4.0的版本中宣称自己是零配置
    • 极小化配置的背后体现出来的就是js工程的标准化。最简单的就是源码目录(比如src)和产出资源目录(比如dist)。成为默认项之后,对整个社区的发展是一件好事
  1. WebAssembly
    • 未来说不定通过loader就能加载c代码模块

参考《Webpack实战:入门、进阶与调优》(居玉皓)