向新型浏览器提供新式代码,以提高网页加载速度

构建适用于所有主流浏览器的网站是开放 Web 生态系统的核心原则。不过,这意味着您需要额外的工作来确保您编写的所有代码都受您计划定位到的每个浏览器支持。如果您想使用新的 JavaScript 语言功能,则需要将这些功能转译为向后兼容的格式,以便在尚不支持这些功能的浏览器中使用。

Babel 是最常用的工具,可将包含较新语法的代码编译为不同浏览器和环境(例如 Node)可以理解的代码。本指南假定您使用的是 Babel,因此如果您尚未将其添加到应用中,则需要按照设置说明操作。如果您在应用中使用 webpack 作为模块捆绑器,请在 Build Systems 中选择 webpack

若要使用 Babel 仅转译用户需要的内容,您需要:

  1. 确定要定位到的浏览器。
  2. @babel/preset-env 与适当的浏览器目标搭配使用。
  3. 使用 <script type="module"> 可停止向不需要转译后的代码的浏览器发送此类代码。

确定要定位到的浏览器

在开始修改应用中代码的转译方式之前,您需要确定哪些浏览器会访问您的应用。分析用户目前使用的浏览器以及您计划定位到的浏览器,以便做出明智的决策。

使用 @babel/preset-env

转译代码通常会导致文件大小大于原始形式。通过尽可能减少编译量,您可以缩减软件包的大小,从而提高网页的性能。

Babel 提供了一些预设,可将插件打包在一起,而不是包含特定插件来选择性编译您使用的特定语言功能。使用 @babel/preset-env 仅添加您计划定位的浏览器所需的转换和 polyfill。

在 Babel 配置文件 .babelrcpresets 数组中添加 @babel/preset-env

{
 "presets": [
   [
     "@babel/preset-env",
     {
       "targets": ">0.25%"
     }
   ]
 ]
}

使用 targets 字段,通过向 browsers 字段添加适当的查询来指定要包含的浏览器版本。@babel/preset-env 与 browserslist 集成,后者是一种开源配置,可供不同工具共享,用于定位浏览器。如需查看兼容查询的完整列表,请参阅 browserslist 文档。另一种方法是使用 .browserslistrc 文件列出您要定位到的环境。

">0.25%" 值会告知 Babel 仅包含支持占全球使用量的 0.25% 以上的浏览器所需的转换。这样可以确保您的软件包不包含针对仅由极少数用户使用的浏览器的转译代码。

在大多数情况下,这种方法比使用以下配置更好:

  "targets": "last 2 versions"

"last 2 versions" 值会针对每个浏览器的最后两个版本转译您的代码,这意味着支持已弃用的浏览器(例如 Internet Explorer)。如果您不希望用户使用这些浏览器访问您的应用,则可能会不必要地增加软件包的大小。

最终,您应选择适当的查询组合,以便仅定位到符合您需求的浏览器。

启用现代 bug 修复

@babel/preset-env 会将多个 JavaScript 语法功能划分到集合中,并根据指定的目标浏览器启用/停用这些功能。虽然这种方法很有效,但如果目标浏览器中仅有一个功能存在 bug,则整个语法功能集都会发生转换。这通常会导致转换的代码比实际需要的多。

@babel/preset-env 中的bugfixes 选项最初是作为单独的预设开发的,它通过将在某些浏览器中损坏的现代语法转换为在这些浏览器中不损坏的最接近的等效语法来解决此问题。结果是,只需进行一些小小的语法调整,即可获得几乎完全相同的现代代码,从而确保在所有目标浏览器中都具有兼容性。如需使用此优化,请确保您已安装 @babel/preset-env 7.10 或更高版本,然后将 bugfixes 属性设置为 true

{
 "presets": [
   [
     "@babel/preset-env",
     {
       "bugfixes": true
     }
   ]
 ]
}

在 Babel 8 中,bugfixes 选项默认处于启用状态。

使用 <script type="module">

JavaScript 模块(也称为 ES 模块)是一项相对较新的功能,所有主流浏览器都支持该功能。您可以使用模块创建可从其他模块导入和导出的脚本,但也可以将它们与 @babel/preset-env 搭配使用,以便仅定位到支持它们的浏览器。

建议您在 .babelrc 文件的 targets 字段中指定 "esmodules" : true,而不是查询特定浏览器版本或市场份额。

{
   "presets":[
      [
         "@babel/preset-env",
         {
            "targets":{
               "esmodules": true
            }
         }
      ]
   ]
}

支持 JavaScript 模块的环境中已经支持使用 Babel 编译的许多较新的 ECMAScript 功能。这样一来,您就可以简化确保仅将转译后的代码用于实际需要它的浏览器的过程。

支持模块的浏览器会忽略具有 nomodule 属性的脚本。反之,不支持模块的浏览器会忽略带有 type="module" 的脚本元素。这意味着,您可以添加模块以及编译后的后备方案。

理想情况下,应用的两个版本脚本应如下所示:

  <script type="module" src="main.mjs"></script>
  <script nomodule src="compiled.js" defer></script>

支持模块的浏览器会提取并执行 main.mjs,并忽略 compiled.js。不支持模块的浏览器则会执行相反的操作。

如果您使用 webpack,则可以在配置中为应用的两个单独版本设置不同的目标:

  • 仅适用于支持模块的浏览器的版本。
  • 包含在任何旧版浏览器中都适用的已编译脚本的版本。由于转译需要支持更多类型的浏览器,因此文件大小较大。

感谢 Connor Clark 和 Jason Miller 的审核。