天天看点

ES6 模块原生支持在浏览器中落地,是时候该重新考虑打包了吗?ES6 模块原生支持在浏览器中落地,是时候该重新考虑打包了吗?

<b>本文讲的是ES6 模块原生支持在浏览器中落地,是时候该重新考虑打包了吗?,</b>

最近一段日子,编写高效的 JavaScript 应用变得越来越复杂。早在几年前,大家都开始合并脚本来减少 HTTP 请求数;后来有了压缩工具,人们为了压缩代码而缩短变量名,甚至连代码的最后一字节都要省出来。

构建 web 应用的常用方式就是使用由 Browserify、Rollup、Webpack 等工具构建的代码包(bundle)。而不使用 SPA(单页面应用)技术的网站则通常由服务端生成 HTML,在其中引入一个 JavaScript 代码包。

我们使用 Webpack 打包的代码包中包括了 3 个 JavaScript 文件,这些文件使用了 ES6 模块:

这个 app 将会显示“Hello world”。在下文中显示“Hello world”即表示脚本加载成功。

配置使用 Webpack 创建一个代码包相对来说比较直观。在构建过程中,除了打包和使用 UglifyJS 压缩 JavaScript 文件之外并没有做别的什么事。

3 个基础文件比较小,加起来只有 347 字节。

在我通过 Webpack 构建之后,我得到了一个 856 字节的代码包,大约增大了 500 字节。增加这么些字节还是可以接受的,这个代码包与我们平常生产环境中做代码装载没啥区别。感谢 Webpack,我们已经可以使用 ES6 模块了。

现在,我们得到了一个“传统的打包代码”,现在所有还不支持 ES6 模块的浏览器都支持这种打包的代码。我们可以开始玩一些有趣的东西了。让我们在 <code>index.html</code> 中加上一个新的 script 元素指向 ES6 模块,为其加上 <code>type="module"</code>。

然后我们在 Chrome 中看看,发现并没有发生什么事。

代码包还是和之前一样加载,“Hello world!” 也正常显示。虽然没看到效果,但是这说明浏览器可以接受这种它们并不理解的命令而不会报错,这是极好的。Chrome 忽略了这个它无法判断类型的 script 元素。

接下来,让我们在 Safari technology preview 中试试:

遗憾的是,它并没有显示另外的“Hello world”。造成问题的原因是构建工具与原生 ES 模块的差异:Webpack 是在构建的过程中找到那些需要 include 的文件,而 ES 模块是在浏览器中运行的时候才去取文件的,因此我们需要为此指定正确的文件路径:

改了文件路径之后它能正常工作了,但事实上 Safari Preview 加载了代码包,以及三个独立的模块,这意味着我们的代码被执行了两次。

现在好了。通过结合使用 <code>type="module"</code> 与 <code>nomodule</code>,我们现在可以在不支持 ES6 模块的浏览器中加载传统的代码包,在支持 ES6 模块的浏览器中加载 JavaScript 模块。

ES6 模块默认在严格模式下运行(因此你不需要加上 <code>use strict</code> 了)。

最外层的 <code>this</code> 指向 <code>undefined</code>(而不是 window)。

最高级变量是 module 的局部变量(而不是 global)。

ES6 模块会在浏览器完成 HTML 的分析之后异步加载与执行。

我认为,这些特性是巨大进步。模块是局部的——这意味着我们不再需要到处使用 IIFE 了,而且我们不用再担心全局变量泄露。而且默认在严格模式下运行,意味着我们可以在很多地方抛弃 <code>use strict</code> 声明。

译注:IIFE 全称 immediately-invoked function expression,即立即执行函数,也就是大家熟知的在函数后面加括号。
译注:SPOF 全称 Single Points Of Failure——单点故障

还没完!我们现在能为 Chrome 提供压缩过的代码包,但是还不能为 Safari Preview 提供单独压缩过的文件。我们如何让这些文件变得更小呢?UglifyJS 能完成这项任务吗?

但是现在 UglifyJS 几乎存在于所有工具链中,那全部使用 ES6 编写的工程应该怎么办呢?

使用 Babili CLI 工具,可以轻松地分别压缩各个文件。

最终结果:

对单个 JS 文件进行压缩取得了很好的效果。文件大小从 856B 降低到了 298B,但是我们还能进一步地加快加载速度。通过使用 ES6 模块,我们可以装载更少的代码,但是看看瀑布图你会发现,request 会按照模块的依赖链一个一个连续地加载。

<b></b>

<b>原文发布时间为:2017年5月04日</b>

<b>本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。</b>

继续阅读