专栏名称: 前端早读课
我们关注前端,产品体验设计,更关注前端同行的成长。 每天清晨五点早读,四万+同行相伴成长。
目录
相关文章推荐
前端大全  ·  深入了解Vite:依赖预构建原理 ·  2 天前  
前端之巅  ·  Vue.js:极速选手还是高风险赌徒? ·  6 天前  
奇舞精选  ·  Mitosis:跨框架的UI组件解决方案 ·  6 天前  
奇舞精选  ·  Mitosis:跨框架的UI组件解决方案 ·  6 天前  
前端早读课  ·  【第3378期】AIGCDesign ... ·  6 天前  
前端大全  ·  20个超好看的落地页/首页模板(附源码) ·  1 周前  
51好读  ›  专栏  ›  前端早读课

【第3381期】Web 上的 ES5现状

前端早读课  · 公众号  · 前端  · 2024-09-24 08:00

正文

前言

主要探讨了 ES5 在当前 Web 开发中的状态,分析了现代 JavaScript 工具链和库的支持情况,并提供了针对 Web 开发者和库作者的最佳实践建议。今日前端早读课文章由 @飘飘翻译分享。

正文从这开始~~

2017 年,我写了一篇文章,向 Web 开发人员展示了如何在生产环境中部署 ES6 代码(又称 ES2015),而无需将其转译为 ES5。这种技术为希望编写现代代码但又不想担心转译器或补丁臃肿问题的网站开发人员带来了解放。

可惜的是,虽然许多网站开发者能够使用这种技术,但大多数 JavaScript 库作者却无法做到。

JavaScript 库作者所面临的约束比网站开发者多得多,因为它们无法控制代码的部署方式。此外,由于许多流行的构建工具建议开发者将 node_modules 目录排除在转译之外,因此库作者被迫采取极其保守的措施 —— 通常将代码转译回 ES5,以避免可能破坏网站。

但那是七年前的事了,自那以后,JavaScript 工具领域取得了巨大的进步。浏览器的生态也发生了巨大的变化。最值得注意的是,IE 11 是最后一个支持 ES5 的浏览器,微软在 2022 年停止对其提供支持,这意味着许多企业终于可以停止支持它了。

那么,当前 Web 上 ES5 的状态如何?对于开发人员来说,在生产环境中编写代码时有哪些最佳实践?

本文将分析我们所拥有的数据,以解答这些问题。同时,基于这些数据,本文还为网站开发人员和 JavaScript 库作者在未来处理遗留浏览器支持问题提出了一些具体的建议。

简单的声明

在深入研究 ES5 的实际使用情况之前,我想澄清的是,无论是编写还是发布 ES5 代码都没有什么本质上的问题。

JavaScript 引擎已经对 ES5 代码进行了更长时间的优化,而不是对现代代码进行优化,因此如果您有仍在工作的旧 ES5 代码,就没有理由仅仅为了使其 “现代化” 而对其进行更新。

【第3370期】ECMAScript 2024 新特性解读!

然而,如果你正在使用 ES6 + 语法编写代码,然后使用构建工具将其转换为 ES5,通常会引入大量的 polyfill 和转译器冗余,这可能会显著增加最终打包文件的大小。

为了说明这一点,这里有一个例子:

 console.log([1, 2, 3].at(-1));

如果你手动将这段代码编译为 ES5,它可能看起来像这样:

 var arr = [1, 2, 3];
console.log(arr[arr.length - 1]);

然而,如果你使用 Babel 将这行代码转译,并配置它添加 polyfills,即使你仅限制为根据源代码中使用情况所需的 polyfills,它将包含 71 个核心 JS 依赖项,并从 31 字节膨胀到 11,217 字节的压缩大小!

本例的目的并不是要批评 Babel 或 core-js。这些工具需要能够支持所有可能的 ES6 + 代码,这要求它们要考虑各种各样的边缘情况(尽管这个特定的例子并没有)。

相反,重点在于强调选择支持旧版浏览器确实会带来一定的成本,而且这个成本可能是相当大的。

【第3366期】JavaScript 混淆:2024年的终极指南

不幸的是,这个问题比代码膨胀还要严重。如果你看看当今流行网站在将代码编译并部署到生产环境中时的数据,你会发现互联网上大多数网站都发送经过编译的 ES5 代码,但仍然无法在 IE 11 上运行 —— 这意味着编译器和补丁膨胀代码被 100% 的用户下载,但没有一个用户从中受益。

数据

要了解 ES5 在 Web 上的现状,需要关注三件事情,因为这些因素在最终生成我们作为 Web 用户所接收到的代码方面都扮演着关键角色:

  • 流行的打包器和构建工具的默认配置

  • 流行的 JavaScript 库中的代码状态

  • 网站所有者部署的代码状态

默认的打包器和构建工具配置

大多数打包器和构建工具都具有极高的可配置性,可以几乎完全控制代码的最终输出。然而,在实践中,大多数开发人员只是使用默认设置,因此默认设置非常重要。

【第2505期】ES6 以上版本代码要不要转码成 ES5?

这些默认值是什么?具体来说,默认值是否会导致代码被编译为 ES5?

为了回答这个问题,我查看了根据最新 JavaScript 调查(2023 年)列出的按流行程度排序的一些最流行的构建工具的输出。

工具默认为 ES5?说明
Browserslist它本身并不是一个构建工具,但被许多构建工具内部使用,是配置浏览器支持目标的最受欢迎的开源工具。defaults 设置不再包含任何 ES5 浏览器。最后一个是 IE 11,在版本 4.21 中被标记为已废弃。
BabelBabel 的文档建议设置一个 targets 选项(使用 Browserslist),但如果未指定,则会将所有代码编译为 ES5。
Webpack默认情况下,webpack 不会对任何代码进行转译。大多数 webpack 用户会包含 babel-loader ,webpack 提供的该示例建议设置 targets: "defaults" 。
TypeScript (tsc)TypeScript 的默认 target 选项是 ES5。
Next.jsNext.js 使用 Babel 进行编译,并默认设置了一个 Browserslist 配置,目标是 “现代浏览器”(即支持 ES 模块的浏览器)。
esbuildesbuild 默认不进行转译。你可以设置自定义目标来启用转译,但 ES5 不作为转译目标支持。
ViteVite 使用了 esbuild,并默认为 “现代浏览器”(即支持 ES 模块的浏览器)设置了自定义目标。如果用户需要支持遗留浏览器,可以安装插件。
Rollup默认情况下,Rollup 不会进行转译。许多 Rollup 用户会安装 @rollup/plugin-babel 插件,这样就会使用 Babel 的默认设置。
ParcelParcel 会自动应用可定制目标的差异化分发。
Closure Compiler默认值为 ECMASCRIPT_NEXT ,这是最新的稳定 ES 功能集。

如表所示,大多数打包工具和构建工具不再默认将代码转译为 ES5 格式了。值得注意的是,一些较新的工具甚至不支持 ES5 格式,这表明这一趋势正在朝着这个方向发展。

话虽如此,Babel 仍然是最流行的 JavaScript 转译工具,因此将 JavaScript 转译为 ES5 在网络上仍然很常见(有关具体细节,请参见下文中的在实际中 ES5 使用情况)。

流行的 JavaScript 库

除了研究流行的构建工具外,我还研究了一些目前使用最广泛的库(再次基于 State of JS 调查,按照大致的流行度排序):

为了测试这些库,我创建了一个打包入口点,仅导入特定的库,并使用了该库文档中的一个示例代码。然后,我使用 Rollup 和 Webpack 对代码进行打包,以测试输出并查看是否包含任何 ES6 + 语法(特别是 IE 11 不支持的任何 ES6 + 语法)。

我发现的是:

包含 ES6 + 语法?说明
Lodash只有 ES5
React只有 ES5
date-fns箭头函数
three.js异步 / 等待,箭头函数,扩展运算符,解构
d3箭头函数,展开,解构
Framer-motion箭头函数,扩展运算符,解构
greensock只有 ES5
dayjs只有 ES5
Zod异步 / 等待,箭头函数,扩展运算符,解构
RxJS箭头函数
immer箭头函数,扩展运算符,解构
luxon异步 / 等待,箭头函数,扩展运算符,解构
react-query只有 ES5(捆绑 Babel 辅助工具)

如上所示的结果表明,许多流行的 JavaScript 库现在正在发布 ES6 + 语法。

这很值得注意,因为正如我之前所说,大多数使用 Babel 对源文件进行转译并在打包时,会明确地配置打包器不要对 node_modules 目录中的任何文件进行转译 —— 这正是历史上库作者们认为他们需要继续转译到 ES5 的主要原因。

例如,截至本文发布时(2024 年 9 月):

  • Webpack 的官方文档建议配置文件中排除 node_modules 。

  • Rollup 的官方文档建议排除 plugin-babel ,并且建议库作者不要发布 ES6 代码。

而 TypeScript( tsc )是 Babel 之后第二受欢迎的转译工具,它只会转译项目自身的代码文件,不会转译项目依赖的文件( node_modules )。

这为任何希望支持 ES5 并使用 Babel 或 tsc 进行代码转译的网站带来了问题。除非他们对构建管道中所有组件之间的交互有深入的理解,并且知道如何正确配置每个组件,否则他们很可能在不意识到的情况下将 ES6 + 代码与 ES5 代码一起打包。

因此,这个问题就产生了:这实际上是否对真实网站造成了问题,还是大多数网站都正确配置了他们的工具?下一节将引用 HTTP Archive 的数据来回答这个问题。

注意:表中的一些库同时发布了 ES5 和 ES6 + 版本,通常将 ES5 版本设置在 package.main 字段,ES6 + 版本设置在 package.module 或 package.exports 字段。在这种情况下,我只查看了在使用默认配置时(因为这是大多数人使用的配置)由打包器加载的脚本的哪个版本(因为打包器现在默认使用 package.module 或 package.exports 而不是 package.main 。

在实际应用中使用 ES5

开发人员用来将 ES6 代码转换为 ES5 的三种主要工具是:

  • Babel

  • TypeScript(tsc)

  • 闭包编译器(谷歌内部称为 JSCompiler)

这三个工具都包含某种形式的 polyfills 和所谓的 ES5 “辅助” 函数,以避免在最终输出中的出现重复。这些工具最常用的 ES5 辅助函数库有:babel-helpers、core-js、regenerator-runtime、tslib 和 $jscomp。

这些辅助库中的许多函数都具有足够的独特性,可以通过查询 HTTP Archive 来检测哪些网站使用了它们。搜索这些辅助函数的存在(而不是标准的 ES5 语法,如 var 或非箭头的 function )有助于区分由手工编写的(通常经过精心优化)的旧 ES5 代码和由转译器生成的新 ES5 代码(通常比较臃肿)。

我在 HTTP Archive 中进行了一次搜索,以了解在基于 CrUX 流行排名的前 10,000 个热门网站中,它们在将脚本打包部署到生产环境中时是否普遍包含这些辅助文件。我还想看看这些网站中是否普遍存在未转译的 ES6 语法。

这是我发现的(完整结果):

  • 89% 的网站至少提供了一个包含未转译的 ES6 语法的 JavaScript 文件。

  • 79% 的网站至少提供一个包含 ES5 辅助代码的 JavaScript 文件。

  • 68% 的网站至少提供了一个包含 ES5 辅助代码和未经转译的 ES6 语法的 JavaScript 文件。

这个最后的发现让我大吃一惊。

再强调一遍我之前说过的话 —— 因为它值得重复一遍 —— 如果浏览器不支持 ES6 + 语法(例如 IE 11),那么在尝试加载包含 ES6 + 语法的脚本文件时,它会出错。如果浏览器确实支持 ES6 + 语法,那么就不需要任何 ES5 辅助代码或任何遗留的 polyfill。完全没有理由同时包含两者。

为了确保此查询结果的准确性,我手动测试了列表中 20 个随机网站,并确认它们确实包含 ES5 辅助代码以及 ES6 语法的一些相同脚本包。我还手动访问了这些网站在 IE 11 中,并确认了这些脚本包确实无法加载。

请记住,这些不仅仅是互联网上的任意网站。它们是全球最受欢迎的 10,000 个网站,占全球所有网络使用量的绝大多数。

这意味着什么?

对于一个网站来说,如果它同时包含 ES5 辅助函数和未经转译的 ES6 语法,那么只有两种可能的解释:

  • 该网站不需要支持 ES5 浏览器,但它们的一些依赖项需要转译为 ES5,因此在输出中会出现 ES5 代码。

  • 该网站旨在支持 ES5 浏览器,但他们没有意识到他们的一些依赖项发布的是未经转译的 ES6 语法,也没有配置他们的打包器在 node_modules 中转译代码。

不管解释是什么,全球最受欢迎的网站中有如此多的网站在加载大量不必要的代码,这强烈表明我们当前工具的默认设置并不奏效。

如果这些数据中有任何积极的一面的话,那就是我很清楚地意识到,停止支持 IE 并不会对大多数企业造成显著的影响。如果这些大型公司显然没有受到这些破损的 IE 体验的影响,那么你的公司也不会受到影响。

建议

对于库作者来说

最初,库作者将代码转译为 ES5 的理由是,大多数网站都需要将代码转译为 ES5。然而,鉴于目前排名前 10000 的网站中有 89% 仍在使用未经转译的 ES6 语法,这一理由已不再适用。

鉴于本文提供的数据,JavaScript 库作者再将代码转译为 ES5 显然已不合适了。

实际上,库作者并不知道被其库导入的网站对浏览器的支持需求,因此让他们为所有使用其库的用户做出这一决定并不合理。同时,库作者不应该假设所有使用其库的用户都能通过复杂构建过程运行该库,因此重要的是,他们发布的代码应该使用完全标准的 JavaScript,并在当前广泛使用的浏览器集中运行。

所以,库作者应该选择哪些目标呢?在我看来,对于库作者来说,最好的解决方案是使用 Baseline—— 具体来说,即在发布的任何代码中仅包含基线中广泛可用的功能。

如果对 Baseline 不熟悉,那么它是万维网联盟 (W3C) 下的 WebDX 社区小组为帮助开发人员轻松识别在桌面和移动设备上所有主流浏览器和渲染引擎中都具有良好支持的特性而做出的努力。如果一个特性在四大主要浏览器的稳定版本中至少已可用 30 个月,那么它就被认为是 Baseline 广泛可用的。

将目标锁定在像 Baseline Widely Available 这样的东西上的主要好处是,它是一个动态的目标,这意味着它不会像目标锁定在 ES5 上(以及目前 Next.js、Vite 和 Parcel 使用的 esmodule 目标)那样被困在过去。

库作者可以使用以下的 Browserslist 查询(适用于所有支持 Browserslist 的工具)来为其构建系统设置目标,以针对 Baseline Widely Available 功能:

 targets: [
'chrome >0 and last 2.5 years',
'edge >0 and last 2.5 years',
'safari >0 and last 2.5 years',
'firefox >0 and last 2.5 years',
'and_chr >0 and last 2.5 years',
'and_ff >0 and last 2.5 years',
'ios >0 and last 2.5 years',
]

注意:有一个公开的功能请求,要求在 Browserslist 中添加基线支持,这将使上述查询简化为 “基线广泛可用”。

如果一个网站需要支持的浏览器多于 Baseline Widely Available 覆盖的那些,那完全没问题。该网站总是可以配置其构建系统,进一步对所导入的任何库进行转译。关键是,这是由网站开发人员而非库作者的最佳决策。

对于网站开发者

许多流行的网站在同一个脚本包中同时提供未经转译的 ES6 语法和 ES5 辅助函数,这一事实清楚地表明,将 node_modules 目录排除在转译之外的做法并不是一种好的做法。

自从 2017 年开始,我就一直在主张这种做法是不可取的,但与我交流的大多数开发者都不愿意采纳我的建议,因为这样做会减慢他们的构建速度。

然而,如今构建工具的速度已经显著提高。此外,网站可以配置构建过程,仅在生产构建时处理 node_modules 中的代码。在开发阶段,代码应该在开发者使用的任何浏览器上运行良好,尤其是如果库作者采纳了我给出的建议并针对广泛可用的基线进行优化的话。

最终思考

正如我之前提到的,本文的目的并不是根据这些发现来责怪或羞辱网站或工具的作者。我也想确保大家清楚,我绝对不是建议网站仍然要支持 IE 11。相反,这些发现表明,对于大多数企业来说,包括拥有全球客户群的大型企业,支持 IE 11 并不是必需的。

我希望读者从这篇文章中获得的主要要点是:

  • ES5 已经不再是开发工具或 JavaScript 库的默认目标了。

如果工具仍然想要提供 ES5 支持,那么它应该是一个可以由具有特定支持需求的特定站点选择启用的功能。

  • 构建工具和库不应使用固定的浏览器支持策略。

这些政策可能会很快过时,这导致了本文数据所揭示的情况。浏览器支持的决定应该由网站本身做出,而不是其使用的工具。对于工具和库来说,一个良好的浏览器支持政策是 “基础广泛可用”。

  • 网站开发者在导入第三方库时,应将这些库作为构建过程的一部分进行处理。

不能假定所有库的作者都拥有与你相同的浏览器支持需求。正如本文的数据所示,在很多情况下,网站开发者可能需要比他们所使用的库拥有更广泛的浏览器支持需求(因此需要进一步转译它们)。

  • 跨浏览器支持并不是仅仅依赖于构建工具就能解决的问题。

如果你需要支持特定的一组浏览器,那么你需要对你的网站进行测试,以确保它在这些浏览器中能够正常运行。

希望本文对那些仍然担心 ES5 支持的人或那些试图说服他人不要担心的人有所帮助!

如果你想知道你的网站是否正在加载包含过时的 ES5 辅助函数和未编译的 ES6 代码的脚本包,你可以在我提供的数据中搜索你的网站,亲自查看。

如果你发现你的网站存在这样的问题,并且根据本文的建议能够进行修复,我很乐意听到你的反馈!

关于本文
译者:@飘飘
作者:@Philip Walton
原文:https://philipwalton.com/articles/the-state-of-es5-on-the-web/

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。