JavaScript模块打包的未来

693 查看

这篇博文介绍了两个未来发展的趋势(HTTP/2 和原生模块)对模块打包产生了何种影响。

1. 为什么要用模块打包

绑定打包指的是把几个带有模块的文件组合到一起,成为一个单一文件。这么做有三个理由:

  1. 在加载所有的模块时,需要检索的文件数量可以降低。
  2. 压缩一个打包文件要比压缩多个单独的文件更有效率一些。
  3. 没用使用的 exports 会在打包过程中被移除,这样能极大程度地节省内存空间。

2. JavaScript 模块

随着 ECMAScript 6 的提出, JavaScript 终于支持内置的模块功能了。(在本文余下内容中,我都将用 JavaScript 模块指代它)尽管如此, JavaScript 的模块化现在还处于一个有点儿尴尬的位置:

一方面, ES6 对模块化进行了语法和语义的标准化。 ES6 制定的规则成为了比较流行的模块书写格式,它的静态结构能自动省略没使用的 exports (JavaScript 中也称这种技术为 “tree-shaking”)

而另一方面,关于如何加载 JavaScript 模块的标准化进程仍在制定过程中,并且截至目前也还没有原生的 JavaScript 引擎支持它们。也就是说,目前唯一使用JavaScript模块的方式是将其编译为一种非原生的格式,比较流行的解决方案有:browserify, webpack, jspm和Rollup。

3. 模块打包的未来发展趋势。

接下来,我们一起看看未来将有很大发展空间的两个潜力股,以及它们对 JavaScript 模块打包的影响。

3.1 潜力股一号种子选手: HTTP/2

HTTP/2 正有条不紊地发展壮大。在上文列举的三个使用模块打包的理由当中,HTTP/2 主要影响其中第一条理由:HTTP/2 跟 HTTP/1相比 ,能极大程度地降低每个网页请求的代价,也就是说下载单个文件和下载多个文件相比,并不能显著地提升性能。既然如此,那我们可以使用更小型的、增量式更新方法。使用打包的话,就不得不下载整个打包后的文件。而不用打包的话,我们可以只下载内容发生改变的那部分(而其它部分的文件仍保存在浏览器缓存中)。

但是 HTTP/2 并不影响使用模块打包的第二和第三个原因。所以以后我们可能会使用混合式的方法,既有利于增量式更新,又能减少下载内容的大小。

3.2 潜力股二号种子选手: 原生 JavaScript 模块

一旦引擎支持原生的 JavaScript 模块的话,这是否会给打包带来影响呢?就连原生运行在浏览器上的 AMD 模块,它都有一套定制化的绑定格式(和自己的小型加载器)。那么原生的 JavaScript 模块比 AMD 模块有什么过人之处吗?答案应该是肯定的。Rollup 支持将多个 JS 模块打包成一个 JS 模块。

以下面两个 JS 模块为例:

Rollup 能将这两个 JS 模块绑定成下面的一个 JS 模块 (注意未使用的 export bar 被删除了):

创始人 Rich Harris 坦言起初,没人想到JavaScript模块会引入打包机制。

当初我研究 Rollup 的时候,连我自己都没想到它能成功。

JS模块处理 imports的方式有助于打包imports 不是 exports 的复制变量, 只能对 imports 执行只读操作

Rollup 官网上,你可以体验一下它的功能。

4. 延伸阅读

  • Building for HTTP/2” 作者 Rebecca Murphey (主要介绍了在新版 HTTP 中的最佳实践发生的彻底改变)
  • Chap. “Modules” in “Exploring ES6” (主要介绍了 ES6 modules 的工作机制)
  • Babel and CommonJS modules” (介绍了如何通过 Babel 实现 交叉编译的 ES6 模块与 CommonJS 模块互通)