发布、传输和安装现代JavaScript以实现更快的应用程序

超过 90% 的浏览器能够运行现代 JavaScript,但传统 JavaScript 的流行仍然是当今 Web 性能问题的最大原因之一。

成都创新互联公司主要从事网站制作、网站设计、网页设计、企业做网站、公司建网站等业务。立足成都服务隆化,十年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:028-86922220

当今的 Web 受到传统 JavaScript 限制,没有任何单一优化可以像使用 ES2017 语法编写、发布和传输网页或软件包那样提高性能。

现代 JavaScript

现代 JavaScript 的特征不是使用特定的 ECMAScript 规范版本编写代码,而是使用所有现代浏览器都支持的语法。Chrome、Edge、Firefox 和 Safari 等现代网络浏览器占据浏览器市场的 90% 以上,依赖相同底层渲染引擎的其他浏览器占另外 5%。这意味着全球 95% 的 Web 流量所来自的浏览器支持过去 10 年来最广泛使用的 JavaScript 语言特性,包括:

  • 类 (ES2015)
  • 箭头函数 (ES2015)
  • 生成器 (ES2015)
  • 块范围 (ES2015)
  • 解构 (ES2015)
  • 剩余和展开参数 (ES2015)
  • 对象速记 (ES2015)
  • 异步/等待 (ES2017)

较新版本的语言规范中的特性在现代浏览器中获得的支持通常不太一致。例如,许多 ES2020 和 ES2021 特性仅在 70% 的浏览器市场获得支持 — 仍然是大多数浏览器,但还不够安全,不能直接依赖这些特性。这意味着尽管“现代”JavaScript 是一个活动目标,但 ES2017 拥有最广泛的浏览器兼容性,同时包含大多数常用的现代语法特性。换句话说,ES2017 目前最接近现代语法

传统 JavaScript

传统 JavaScript 是明确避免使用上述所有语言特性的代码。大多数开发人员使用现代语法编写源代码,但将所有内容编译为传统语法以增加浏览器支持。编译为传统语法确实会增加浏览器支持,但效果通常比我们想象的小。在许多情况下,支持度从 95% 左右增加到 98%,但同时产生了大量成本:

  • 传统 JavaScript 通常比等效的现代代码大 20% 左右,而且速度更慢。工具缺陷和错误配置通常会进一步扩大这一差距。
  • 安装的库占典型生产 JavaScript 代码的 90%。库代码会由于polyfill 和 helper 重复而产生更高的传统 JavaScript 开销,而发布现代代码可以避免这个问题。

npm 上的现代 JavaScript

Node.js 标准化了一个 "exports" 字段来定义软件包的入口点:

{
"exports": "./index.js"
}

"exports" 字段引用的模块意味着 Node 版本至少为 12.8,它支持 ES2019。这意味着使用 "exports" 字段引用的任何模块都可以使用现代 JavaScript 编写。软件包使用者必须假定具有 "exports" 字段的模块包含现代代码并在必要时进行转换。

仅现代

如果要发布采用现代代码的软件包,并让使用者在将其用作依赖项时处理转换,则仅使用 ​​"exports"​​ 字段。

{
"name": "foo",
"exports": "./modern.js"
}

不推荐这种方法。在完美的世界中,每个开发人员都已经将编译系统配置为将所有依赖项 (node_modules) 转换为所需语法。但是,目前情况并非如此,仅使用现代语法发布软件包将使其无法在通过旧版浏览器访问的应用程序中使用。

具有传统回退的现代代码

将 "exports" 字段与 "main" 一起使用,以便使用现代代码发布软件包,但还包括用于旧版浏览器的 ES5 + CommonJS 回退。

{
"name": "foo",
"exports": "./modern.js",
"main": "./legacy.cjs"
}

具有传统回退的现代代码和 ESM 捆绑程序优化

除了定义回退 CommonJS 入口点,还可以使用 "module" 字段指向类似的传统回退捆绑包,但该捆绑包使用 JavaScript 模块语法 (import 和 export)。

{
"name": "foo",
"exports": "./modern.js",
"main": "./legacy.cjs",
"module": "./module.js"
}

许多捆绑程序(如 webpack 和 Rollup)依赖该字段来利用模块特性和实现摇树优化。这仍然是一个传统捆绑包,不包含除了 import/export 语法之外的任何现代代码,所以使用这种方法来传输具有传统回退、但仍然针对捆绑进行了优化的现代代码。

应用程序中的现代 JavaScript

第三方依赖项构成了 Web 应用程序中绝大多数的典型生产 JavaScript 代码。虽然 npm 依赖项在历史上一直以 ES5 语法的形式发布,但这不再是一个安全假设,并且依赖项更新可能会破坏应用程序的浏览器支持。

随着越来越多的 npm 包转向现代 JavaScript,确保构建工具设置为能够处理它们很重要。您所依赖的一些 npm 包很有可能已经在使用现代语言特性。有许多选择可使用 npm 中的现代代码而不会破坏应用程序在旧版浏览器中的体验,但总体思路是让编译系统将依赖项转换为与源代码相同的目标语法。

webpack

从 webpack 5 开始,现在可以配置 webpack 在生成捆绑包和模块的代码时将使用的语法。这不会转换您的代码或依赖项,只影响由 webpack 生成的“粘附”代码。要指定浏览器支持目标,请在您的项目中添加一个 browserslist 配置,或者直接在 webpack 配置中添加:

module.exports = {
target: ['web', 'es2017'],
};

还可以将 webpack 配置为生成优化的捆绑包,当以现代 ES 模块环境为目标时,这些捆绑包会省略不必要的包装函数。这也将 webpack 配置为使用