爱彼迎将JavaScript代码打包工具从Webpack改用Metro,缩短了构建时间

更新日期: 2022-06-14阅读: 1.1k标签: 打包

与许多大规模公司一样,随着代码库不断变大,爱彼迎也在打包工具方面经历了阵痛。即使代码库增至四倍,爱彼迎在2018年将JavaScript代码打包工具从webpack迁移到Metro后,还是加快了对前端的UX更改。

构建性能显著提升后,从交互时间(TTI)这个指标来看,UI更改速度加快了80%。即使是最慢的生产级构建,编译49000个模块(JavaScript文件)现在也快了55%,从使用Webpack时的30.5分钟缩短至13.8分钟。

至于使用Metro构建的那些页面,爱彼迎自己的页面性能得分(PPS)也有所提高(提高约1%)。


图1

作为参考,在2018年左右代码库增至四倍之后,简单一行代码更改的平均页面刷新时间在30秒到2分钟之间,具体取决于项目大小。

爱彼迎软件工程师Rae Liu在最近的这篇 博文 (中介绍了Webpack和Metro的一些差异,并讨论了一些迁移挑战。


一、Metro简介

Metro由Meta开发,是面向react Native的开源JavaScript代码打包工具。本文介绍Metro的自定义版本,因为爱彼迎的架构不包含React Native。降了与本公司的团队合作外,爱彼迎的工程师还直接与Meta的Metro工程师合作,进一步开发这项技术

Metro按以下顺序将打包分为三个步骤:解析、转换和序列化。

  • 解析:解析import/require语句。
  • 转换:转译代码(源到源编译器将现代Typescript/JavaScript源代码转换成JavaScript,并与旧浏览器向后兼容),典型的工具是babel
  • 序列化:将转换后的文件组合成包。

在开发过程中,爱彼迎工程师创建了一个带自定义端点的Metro服务器系统,以处理构建依赖图和源映射、转换以及捆绑JS和css文件。至于生产级构建,他们将Metro作为Node api来运行,以处理解析、转换和序列化。

迁移分两个阶段进行。最要紧的是Metro开发服务器,因为缓慢的Webpack开发服务器是导致开发生产力成本高昂的根源。第二个迁移阶段致力于让Metro在功能上与Webpack相当,并在生产环境下在Metro和Webpack之间运行A/B测试。


二、Metro和Webpack的两大区别

按需处理JavaScript包

Webpack在启动时预编译整个项目,而Metro只编译需要的内容。也就是说,JavaScript包严格上来说就是序列化的依赖图,其中入口点是这张图的根(root)。

在爱彼迎,每个前端项目都有一个Node服务器来匹配通向特定入口点的路由。请求网页时,dom包含带有开发JavaScript URL的脚本标签。Webpack需要知道所有页面的所有入口点,之后才能开始打包,而Metro只需要一个入口点,就可以根据请求处理JavaScript包。

开发人员对页面A进行了更改,但下图中看不到:


在上图的1a和1b中,浏览器加载页面A(1),从打包工具请求entryPageA.js文件(2),打包工具使用适当的包响应浏览器(4)。图1a和图1b的区别在于操作(3),因为 Webpack图编译了页面B和C的入口点,而Metro并非如此,因为开发人员在示例中只修改了页面A。

爱彼迎最大的前端项目之一有26000个独特的模块,每页的模块中位数约7.2个模块。由于使用了服务器端渲染,爱彼迎最终要处理的模块数量翻番,达到大约48000个。在将Metro的按需编译模型付诸实施之后,现在减少了大约70%的工作量。

多层缓存


爱彼迎利用Metro的多层缓存功能以及持久性和非持久性缓存。Metro允许工程师定义缓存实现,包括混合不同类型的缓存层,这样提供了更高的缓存灵活性。

爱彼迎按优先级对缓存层排序。如果在一个缓存层中没有找到结果,将使用下一层,直至找到结果。与没有缓存的默认Metro实现相比,在一个编译22000个文件的项目中,命中远程只读缓存可使服务器构建速度提高56%。

第三个缓存层是远程只读缓存而不是读写缓存,因为写入到远程缓存会带来昂贵的网络调用,尤其是在慢速网络上。这个决定在开发中另外节省了17%的构建时间。

Webpack有一个缓存层,不过它与Metro提供的缓存层不一样。


三、包拆分

爱彼迎的博文中详述的技术挑战之一是包拆分(Bundle Splitting)。这是通过动态导入边界拆分包的过程(又叫代码拆分)。开箱即用的Metro解决方案为每个入口点生成约5MiB 的巨大包,这对浏览器资源和网络延迟造成了负担,无法进行HTTP缓存。


在上图中,import(‘./file’) 表示动态导入边界。左侧的包(3a)被拆分成右侧的三个小包(3b)。执行import('./file') 语句时请求额外的包。

假设fileA.js发生了更改,需要重新下载整个包,以便浏览器获取fileA.js中的更改。如图3b所示,由于包由动态导入拆分,fileA.js中的更改只导致重新下载fileA.js包。其余的包可以重用浏览器缓存内容。

在生产环境下,没有开发服务器,包是预先构建的。爱彼迎工程师从Webpack的包拆分算法中获得了灵感,实现了一种类似的机制来拆分Metro依赖图。与动态导入边界的开发拆分相比,爱彼迎上生成的包大小减少了约20%(由1549 KB变成1226 KB)。

开发包的优化方式不一样,因为运行包拆分算法需要时间,工程师们不想在开发中浪费时间来拆分包大小。在开发情形下,页面加载性能的优先级高于包大小实现最小化。

Metro和Webpack在包大小方面的指标具有可比性。

标题:  Airbnb Moves from Webpack to Metro, Enjoys Shorter Build Times   ,作者:Jessica Wachtel

链接: https://fly63.com/article/detial/11728

用Cordova打包Vue项目

现在的打包Vue项目目前流行的就是使用weex和cordova。weex是阿里提供并且Vue的作者也极力推荐的,有兴趣的可以去学习使用一下。下面说说怎么使用cordova打包Vue项目

Webpack 打包含动态加载的类库

在编写库的时候,我们有时候会希望按需加载某些依赖,例如如果代码的运行环境不支持某些功能的话,就加载相关的Polyfill。webpack作为当前最流行的打包工具,早已支持动态加载的功能了。本文将讨论一种用webpack打包含动态加载的类库的方法。

webpack如何编译ES6打包

随着ES的普及我们越来越多的开始使用ES6的语法了,当然也随着mvvm框架的流行少不了js模块化,那js模块化又有那些呢?在很早的时候大家都用的命名空间,现在也有人用(库名.类别名.方法名)

解决webpack打包速度慢的解决办法

webpack在打包的时候第一次总是会做很长的准备工作,包括加载插件之类的。在刚接触webpack的时候总是webpack一下-测一下-改一下-再webpack一下,这种方式最后让很多人崩溃了觉得webpack一点都不好用

vue实现分环境打包步骤

在新建好的项目中,一般执行npm run build就是打包了,但此时只能打包到一个环境,不同环境需要配置不同的地址,可以手动更改接口的地址,也可以自行配置命令而不需要每次打包进行地址切换

前端js打包工具

打包工具可以更好的管理html,css,javascript,使用可以锦上添花,不使用也没关系。html好比是房子的地基,css和 javascript是房子的建筑材料,这三个部分一起组成个漂亮的房子

webpack4 打包静态资源

准备一个空文件夹,然后执行下列命令:然后创建一个 dist 目录,并在里面创建一个 indedx.html:接着创建一个 src 目录,在里面创建一个 lib 文件夹,创建一个 until.js:再创建 components 文件夹,再写入几个 js:

vue-cli3.0中自定css、js和图片的打包路径

我们有时候因为一些特殊需求,可能需要将js/css/img等资源文件都打包到根路径下,但vue-cli3.0的路径配置中仅有assetsDir配置项能够配置所有的静态文件所在的文件夹,并不能针对css/js/img等资源文件分别来做设置,那么请看我如何尝试的吧!

Webpack安装配置及打包详细过程

前端经过漫长的发展,涌现出了很多实践方法来处理复杂的工作流程,让开发变得更加简便,其中,模块化可以使复杂的程序细化成为各个小的文件,而webpack并不强制你使用某种模块化方案,而是通过兼容所有模块化方案让你无痛接入项目

webpack动态加载打包chunk命名

最近,遇到复杂h5页面开发,为了优化H5首屏加载速度,想到使用按需加载的方式,减少首次加载的JavaScript文件体积,于是将处理过程在这里记录一下,涉及到的主要是以下三点:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!