Rollup vs. Parcel vs. webpack
对于那些没有JavaScript背景的用户来说,打包工具可以从应用程序的入口文件递归地跟踪所有导入的文件,并将它们打包成一个文件。 打包工具还可以通过删除不必要的空格,换行,注释,还可以切割成小块的文件而不会影响其功能。
让我们通过一个简单的例子来理解它:
var test = [];for (var i = 0; i < 100; i++) {test[i] = i;}
我们创建了一个数组叫 test,然后初始化它的值为从 0 到 99。压缩后的代码如下:
for(var a=[i=0];++i<20;a[i]=i);
字符和行数更少。你可能要说代码不可读了,但是谁在乎呢?代码写完了然后打包,压缩后的代码更容易被浏览器加载和解析。
现在你很容易就理解了打包工具的重要性了,对吗?
假设你的代码未打包,然后以多个文件的形式托管在服务器上。代码运行时为了导入每个文件,浏览器必须为每个文件向服务器发送单独的HTTP请求。这种传输的效率与所请求文件的数量和大小成正比。对于诸如Facebook之类的大型应用程序,其性能和用户体验可能会是一场灾难。
但是,通过使用打包工具,应用程序的性能将大大提高,因为现在浏览器只需要请求一个文件即可向用户显示你的应用程序。 此外,获取一个只有几KB的压缩文件比实际的文件要快,而实际的文件可能会有几MB,从而缩短了应用程序的加载时间。
既然我们可以自己做为什么还需要打包工具?
当然可以,但是你的代码库庞大时,手动压缩代码不是灵活的解决方案。 让打包工具为你服务!
取决于具体的使用场景,选择正确的打包工具会极大改善你的应用程序。
打包工具的配置
Parcel 胜出。因为它根本无需配置文件。只需要安装 Parcel 后然后编译,它开箱即用地为你完成一切工作。
webpack 和 Rollup 都需要一个配置文件,用于指定入口,输出,加载器,插件,转换工具等。不过有点区别:
Rollup 有 import/export 的node兼容库,但 webpack 没有。Rollup 支持在配置中使用相对路径,但 webpack 不行 — 那就是为什么你需要使用 path.resolve 或者 path.join
webpack 配置可能会变得很复杂,但是支持第三方导入,图片导入,CSS预处理等众多功能。
我在用 Rollup 打包项目时遇到了困难,那个项目用到了 axios,还有其他第三方库。我不得不搜索资料然后安装了许多 Rollup 插件才成功了,这还是在舍弃了一些文件导入的前提下。
死代码消除
死代码消除,也常称为 Tree shaking,对于优化文件包大小和性能来说非常重要。
Parcel 在这局是胜出者。它为 ES6 和 CommonJS 模块两者都支持 tree shaking。这点是革命性的,因为 npm 中的大多数代码仍然在用 CommonJS 格式。
在消除死代码时 Parcel 的大部分工作利用了多个工作线程来并发运行,同时会缓存在文件系统里。这意味打包很快,重新打包超快。
Rollup 在这项排名第二。开箱即用,它会静态分析要导入的代码,并将所有未使用的内容排除在外。 这样可避免你在配置中写入更多代码,增加额外的依赖关系并增加应用程序的大小。
webpack 做 tree shaking 需要额外的一些工作:
使用 ES6 句法(即 import 和 export)在 package.json 中设置 SideEffects引入一个支持删除死代码的工具(例如UglifyJSPlugin)
Rollup 和 webpack 更加专注与为 ES6 做 tree shaking,因为做 ES6 的静态分析容易很多,但是为了发挥更大作用,我们也需要分析 CommonJS 的依赖,这两个工具都需要导入插件。
但是,考虑到 JavaScript 是动态的,这门语言的每种结构在运行时会可以被修改。
这就意味着一个作为指针被导入的类,无法被静态分析以删除其没有用到的动态和静态属性。最好不要依赖于打包工具,最好在写代码之前先把组件关系图画一下,然后分析它们以获得最佳效果。
代码分拆
随着应用程序的增长,包的大小也会随之增加,导入的第三方包也会增多。 应用程序的加载时间与包大小成正比。
代码拆分可帮助浏览器仅延迟加载使应用程序运行所需的内容,从而显著提高性能和用户体验。
webpack以最少的工作量和更快的加载时间在这方面成为赢家。 它提供了三种方法来启用代码拆分:
定义入口文件 - 使用 entry 配置项手动拆分代码使用 CommonsChunkPlugin动态导入 - 在模块内部使用行内函数调用在 Rollup 的代码分拆中,你的代码块自身就是标准的 ES 模块,使用浏览器内置的模块加载器,没有任何额外的开销,但是仍然能够充分利用 tree shaking 的功能。对于尚不支持 ES 模块的浏览器,你也可以用 SystemJS 或其他的 AMD 加载器。它是完全自动化的,并且代码重复为零。
Parcel 支持零配置代码拆分。 它的代码拆分是通过使用动态 import() 函数语法建议规范来控制的,该建议类似于常规的 import 语句或 require 函数,但是返回 Promise。 这意味着该模块是异步加载的。
使用 Rollup 和 Parcel 而不是 webpack 进行代码拆分看起来很有诱惑力,但是它们都只是在最近才引入了此功能,并且据说还有一些问题待解决。 所以,可以安全地使用旧的Webpack。
我发现一个令人信服的事实是,对于启用了代码拆分的相同代码,使用 webpack 的构建时间最少,其次是Rollup,最后是Parcel。
实时重新加载
在开发阶段,你修改代码后应用自动实时重新加载这点很棒。一个有实时重新加载功能的打包工具可以自动帮你完成这个操作。
除其他对于调试和开发必不可少的工具外,打包工具还以开发服务器的形式为您提供了一个运行时环境。
通过内置开发服务器,Parcel考虑得很周到,当你更改文件时,该服务器会自动重新打包你的应用程序。 但是在使用HTTP日志记录,挂钩和中间件时,存在一些问题。
在使用 Rollup 时我们需要安装并配置 rollup-plugin-serve,它提供了实时重新加载的功能。不过它需要另一个插件 rollup-plugin-livereload 才能工作,也就是说它不是一个独立的插件,需要另外的依赖才能工作。
使用webpack,你只需要添加一个名为webpack-dev-server的插件,它提供了一个默认开启了实时重新加载功能的简单版开发服务器。更好的是什么呢?你可以在开发服务器启动并运行后使用Hooks进行某些操作,添加中间件,还可以指定运行我们的开发服务器时要使用的文件。Webpack的这种可定制性胜过Rollup和Parcel
热模块替换
热模块替换(HMR)通过在运行时自动更新浏览器中的模块而无需刷新整个页面,从而改善了开发体验。 在代码中进行少量更改时,可以保留应用程序状态。
你可能会问热模块加载与实时重新加载有何不同。
是这样的,当一个文件更改时实时重新加载会重新载入整个应用程序。例如,如果你位于应用程序的第五个访问层级,然后保存一处修改,这时实时重新加载会重启整个应用,加载后回到落地页/首页。
对应的是,热模块替换仅刷新已更改的文件,同时仍保持应用程序的状态。 例如,如果你位于应用程序的第五个访问层级并保存了CSS的修改,则状态不会更改:你仍在同一页面上,但是新样式将会应用。
webpack拥有自己的Web服务器,称为webpack-dev-server,通过它可以支持热模块替换。它可以在开发中用作实时重新加载的替代品。
Parcel已经内置了对热模块替换的支持,Rollup上个月发布了一个插件 rollup-plugin-hotreload来支持热加载。
由于在 Rollup 和 Parcel 这类打包工具中是新功能,安全起见我仍然选择 webpack,因为我在开发时不想遇到能避免的问题。
模块转换
打包工具通常只知道如何读取 JS 文件。转换器(transformer)本质上是老师,告诉打包工具如何处理 JS 之外的文件,如何把它们添加到应用程序的依赖图表中然后打包。
例如,在上图中你可以看到一份 webpack 配置,它在第13行到15行描述了如何读取CSS文件。它的基本内容是“webpack,当你遇到一个解析为 .css 的文件时,使用上面导入的 css-loader 读取它然后导出为一个字符串。”类似的,HTML 加载器会告诉 webpack 在应用遇到 .html 文件时如何读取并导出为字符串。
Parcel 非常巧妙地处理转换过程。 Rollup 和 webpack 需要你指定要转化的文件类型,安装并配置插件来转换它们。但 Parcel 和它们不同,它为许多常见的转换和编译器提供了内置的支持。
当在模块中找到配置文件(例如.babelrc,.postcssrc,.posthtml等)时,Parcel会自动运行对应的转换器。 除了.babelrc中指定的任何转换之外,Parcel始终在所有模块上使用Babel将现代JavaScript句法编译为浏览器支持的格式。
总结
如下是我实验得出的结论:
构建一个简单的应用并让它快速运行起来?使用 Parcel。
构建一个类库只需要导入很少第三方库?使用 Rollup。
构建一个复杂的应用,需要集成很多第三方库?需要代码分拆,使用静态资源文件,还有 CommonJS 依赖?使用 webpack。
举报/反馈

小象Web开发

756获赞 123粉丝
关注 Web 开发,分享编程技巧
关注
0
0
收藏
分享