ES5 在 Web 上的现状

最后一个支持 ES5 的浏览器 IE 11 在 2022 年被微软停止支持,那么今天 Web 上的 ES5 现状如何?在构建生产代码时,Web 开发者的最佳实践是什么?

本文将通过数据来回答这些问题,并基于这些数据为网站开发者和库作者提供一些具体的建议,帮助他们在未来处理旧版浏览器的支持问题。

简要声明

在深入探讨 ES5 使用的实际数据之前,本文需要澄清一点,编写或发布 ES5 代码本身并没有什么错。

JavaScript 引擎对 ES5 代码的优化时间比对现代代码的优化时间长得多,所以如果你有旧的 ES5 代码仍在工作,没有必要仅仅为了使其“现代化”而更新它。

然而,如果你使用 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 个 core-js 依赖项,并从 31 字节增加到11,217 字节的最小化代码!

这个例子的重点不是要说 Babel 或 core-js 不好。这些工具需要支持所有可能的 ES6+代码,这要求它们考虑各种边缘情况(尽管这个特定的例子没有任何边缘情况)。

相反,重点是强调选择支持旧版浏览器是有代价的,而且这个代价可能非常高。

不幸的是,问题实际上比代码膨胀更糟糕。如果查看下面的数据,了解今天流行的网站实际上是如何转译和部署他们的代码到生产环境,你会发现大多数网站在互联网上发布的代码是转译为 ES5 的,但仍然无法在 IE 11 中工作——这意味着转译器和 polyfill 膨胀被 100%的用户下载,但没有一个用户受益。

数据分析

要了解 ES5 在 Web 上的现状,需要关注以下三个方面,因为它们都在我们作为 Web 用户接收到的最终代码输出中起着关键作用:

  • 流行的打包器和构建工具的默认配置
  • 流行 JavaScript 库中的代码状态
  • 网站所有者部署的代码状态

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

大多数打包器和构建工具都具有极高的可配置性,几乎可以对最终输出的代码进行无限控制。然而,在实际操作中,大多数开发者只是使用默认配置,因此默认配置非常重要。

那么这些默认配置是什么?具体来说,这些默认配置是否会将代码转译为 ES5?

可以通过State of JS 调查(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 模块的浏览器)。如果需要支持旧版浏览器,Vite 允许用户安装一个插件。
RollupRollup 默认不进行转译。许多 Rollup 用户安装@rollup/plugin-babel,在这种情况下使用 Babel 的默认配置。
ParcelParcel自动应用差异化服务,并具有可自定义的目标。
Closure Compiler默认设置为ECMASCRIPT_NEXT,即最新的一组稳定的 ES 特性。

如上表所示,绝大多数打包器和构建工具默认不再转译为 ES5。值得注意的是,较新的工具根本不支持 ES5,这表明趋势正在向这个方向发展。

尽管如此,Babel 仍然是最流行的 JavaScript 转译工具,因此在 Web 上转译为 ES5 仍然相当普遍(详见野外的 ES5 使用情况)。

流行的 JavaScript 库

除了查看流行的构建工具外,还查看了一些当今最流行的库(同样基于State of JS 调查,按受欢迎程度大致排序):

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

结果:

包含 ES6+语法?备注
Lodash仅 ES5
React仅 ES5
date-fns箭头函数
three.jsasync/await,箭头函数,展开运算符,解构赋值
d3箭头函数,展开运算符,解构赋值
Framer-motion箭头函数,展开运算符,解构赋值
greensock仅 ES5
dayjs仅 ES5
Zodasync/await,箭头函数,展开运算符,解构赋值
RxJS箭头函数
immer箭头函数,展开运算符,解构赋值
luxonasync/await,箭头函数,展开运算符,解构赋值
react-query仅 ES5(打包了 Babel 助手)

如上所示,许多流行的 JavaScript 库现在发布的是 ES6+语法。

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

截至 2024 年 9 月:

  • Webpack 的babel-loader文档推荐的配置排除了node_modules
  • Rollup 的plugin-babel文档建议排除node_modules,并且建议库作者不要发布 ES6 代码。

而 TypeScript(tsc),作为仅次于 Babel 的第二大转译工具,只会转译项目自己的代码文件。它不会转译node_modules中的项目依赖项。

这就为任何希望支持 ES5 并使用 Babel 或tsc转译代码的网站带来了问题。除非他们对构建管道的各个部分如何相互作用有深刻的理解,并且知道如何正确配置每一个部分,否则他们可能会在不知不觉中将 ES6+代码与 ES5 代码一起打包。

那么,这是否真的对实际网站造成了问题,还是大多数网站正确配置了他们的工具?下一节将通过HTTP Archive的数据来回答这个问题。

注意: 上表中的一些库发布了 ES5 和 ES6+版本,通常 ES5 版本设置在package.main字段,而 ES6+版本设置在package.modulepackage.exports字段。在这些情况下,我只查看了使用默认配置时打包器拉取的脚本版本(因为这是大多数人使用的),而今天的打包器默认使用package.modulepackage.exports而不是package.main(参见:[1],[2],[3])。

野外的 ES5 使用情况

开发者用来将 ES6+代码转译为 ES5 的三大主要工具是:

  • Babel
  • TypeScript(tsc)
  • Closure Compiler(即 Google 内部的 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 助手代码或任何旧版 polyfills。绝对没有理由同时包含两者。

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

请记住,这些不仅仅是互联网上的随机网站。这些是全球最受欢迎的 10,000 个网站

这意味着什么?

对于一个网站来说,提供包含 ES5 助手和未转译 ES6+语法的代码,实际上只有两种可能的解释:

  1. 该网站不需要支持 ES5 浏览器,但他们的一些依赖项转译为 ES5,因此 ES5 代码出现在他们的输出中。
  2. 该网站打算支持 ES5 浏览器,但他们没有意识到一些依赖项发布了未转译的 ES6+语法,并且他们没有配置打包器来转译node_modules中的代码。

无论是哪种解释,全球许多最受欢迎的网站都在提供大量不必要的代码,这强烈表明我们当前工具推荐的默认配置并不起作用。

如果从这些数据中能找到一丝安慰,那就是显而易见的是,放弃对 IE 的支持不会对大多数企业产生明显影响。如果所有这些大公司显然没有受到这些 IE 体验破坏的影响,那么你的公司也可能不会。

建议

对于库作者

库作者应将代码转译为 ES5 的最初理由是大多数网站需要转译为 ES5。然而,鉴于目前前 10,000 个网站中有 89%发布了一些未转译的 ES6+语法,这一理由已不再有效。

根据本文提供的数据,JavaScript 库作者不再需要将代码转译为 ES5。

实际上,库作者对导入它们的网站的浏览器支持需求没有信息,因此不应该为其所有用户做出这个决定。同时,库作者也不应该假设所有用户都能够通过复杂的构建过程运行它们的库,因此发布的代码应使用完全标准的 JavaScript,并在当前广泛使用的浏览器中工作。

那么库作者应该选择什么目标?在我看来,库作者的最佳解决方案是使用Baseline——具体来说,只包括Baseline Widely Available特性在任何发布的代码中。

如果你不熟悉 Baseline,这是 W3C 内的WebDX 社区组的一项努力,旨在帮助开发者轻松识别所有主要浏览器和浏览器渲染引擎在桌面和移动设备上稳定且广泛支持的特性。如果某个特性在所有四个主要浏览器的稳定版本中至少存在 30 个月,则被认为是Baseline Widely Available

针对Baseline Widely Available的主要好处是它是一个动态目标,这意味着它不会像针对 ES5 那样被困在过去(这也是 Next.js、Vite 和 Parcel 使用的esmodule目标目前正在发生的情况)。

库作者可以通过以下Browserslist查询配置他们的构建系统,以现在针对Baseline Widely Available特性(适用于任何支持 Browserslist 的工具):

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",
];

注意: 有一个开放的功能请求,希望将 Baseline 支持添加到 Browserslist,这将使上述查询简化为“baseline widely available”。

如果某个网站需要支持比Baseline Widely Available覆盖的更多浏览器,这完全没问题。该网站可以始终配置其构建系统以进一步转译任何导入的库。关键是这个决定最好由网站开发者做出,而不是库作者。

对于网站开发者

许多网站开发在同一个脚本包中同时提供未转译的 ES6+语法和 ES5 助手代码,这清楚地表明排除node_modules目录不进行转译的做法并不是一个好做法。

然而,如今构建工具已经变得显著更快。此外,网站可以配置他们的构建,只在生产环境中处理node_modules中的代码。在开发中,代码应该在开发者使用的任何浏览器上运行良好,特别是如果库作者遵循我上面给出的建议并针对Baseline Widely Available

主要观点

  • ES5 不再是构建工具或 JavaScript 库应该默认针对的目标。 如果工具仍然希望提供 ES5 支持,这应该是有特定支持需求的单个网站可以选择的。
  • 构建工具和库不应该使用固定的浏览器支持策略。 这些策略很快就会过时,这导致了本文数据中突出的问题。浏览器支持决策应该由网站本身做出,而不是它使用的工具。一个好的浏览器支持策略是Baseline Widely Available。
  • 导入第三方库的网站开发者应该将这些库作为其构建的一部分进行处理。 不能假设所有库作者都有与你相同的浏览器支持需求。正如本文数据所示,在许多情况下,网站开发者可能比他们导入的库有更广泛的浏览器支持需求(因此需要进一步转译它们)。
  • 跨浏览器支持不应该完全依赖于你的构建工具来处理。 如果需要支持特定的一组浏览器,那么你需要测试你的网站以确保它在这些浏览器中正常工作。

参考

The State of ES5 on the Web

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/428556.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java数据结构专栏介绍

专栏导读 在软件工程的世界里,数据结构是构建高效、可靠程序的基石。"Java数据结构"专栏致力于为Java开发者提供一个全面、深入的学习平台,帮助他们掌握各种数据结构的原理、实现及其在Java中的应用。通过这个专栏,读者将能够提升…

【第34章】Spring Cloud之SkyWalking分布式日志

文章目录 前言一、准备1. 引入依赖 二、日志配置1. 打印追踪ID2. gRPC 导出 三、完整日志配置四、日志展示1. 前端2. 后端 总结 前言 前面已经完成了请求的链路追踪,这里我们通过SkyWalking来处理分布式日志; 场景描述:我们有三个服务消费者…

Hive企业级调优[3]—— Explain 查看执行计划

Explain 查看执行计划 Explain 执行计划概述 EXPLAIN 命令呈现的执行计划由一系列 Stage 组成。这些 Stage 之间存在依赖关系,每一个 Stage 可能对应一个 MapReduce Job 或者一个文件系统的操作等。如果某 Stage 对应了一个 MapReduce Job,则该 Job 在 …

OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【内核通信机制】下

往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~ 子系统开发内核 轻量系统内核(LiteOS-M) 轻量系统内核&#…

微信支付开发-后台统计工厂实现

一、数据库设计图 二、后端统计工厂逻辑 1、统计父抽象类 a、StatisticsHandle.php 2、统计工厂通道类 a、StatisticsFactory.php 3、查询实现类 a、答题统计(Answer.php) 三、后端统计工厂代码实现 1、统计父抽象类(StatisticsHandle.php) <?php /*** 统计父抽象类* Use…

VirtualBox 7.1.0 发布下载 - 开源跨平台虚拟化软件

VirtualBox 7.1.0 (macOS, Linux, Windows) - 开源跨平台虚拟化软件 Oracle VM VirtualBox 7 请访问原文链接&#xff1a;https://sysin.org/blog/virtualbox-7/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 2024 年 9 月 …

Redis面试真题总结(三)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 什么是缓存雪崩&#xff1f;该如何解决&#xff1f; 缓存雪崩是指…

算法课习题汇总(2)

整数划分问题 将正整数n表示成一系列正整数之和&#xff0c;nn1n2…nk(n1>n2>…>nk,k>1)。正整数n的这种表示称为正整数n的划分。 思路&#xff1a; n表示待划分数&#xff0c;m表示最大减数。 #include<iostream> using namespace std;int q(int n, int…

面试题给图例举测试用例或测试点

目录 从功能测试的角度考虑&#xff1a; 从性能角度考虑&#xff1a; 从兼容性的角度考虑&#xff1a; 从自动化角度考虑&#xff1a; 从安全性角度考虑&#xff1a; 用户体验的角度测试&#xff1a; 面试通常会有技术和人事两种&#xff0c;侧重点不一样。 今天聊一下测…

Qt日志输出及QsLog日志库

目录 Qt日志输出及QsLog日志库日志输出格式化日志普通格式化条件格式化环境变量设置格式化日志输出位置日志输出对象信息禁用输出 QsLog日志库使用方法1. 将QsLog目录添加到项目中2. 配置CMakeLists.txt文件3. 配置.pro文件4. 日志记录器的配置5. 运行程序6. 启用行号和文件名C…

有奖直播 | onsemi IPM 助力汽车电气革命及电子化时代冷热管理

在全球汽车行业向电气化和智能化转型的浪潮中&#xff0c;功率管理技术的创新和应用成为了关键驱动力。作为全球领先的半导体解决方案供应商&#xff0c;onsemi&#xff08;安森美&#xff09;致力于通过其先进的智能功率模块&#xff08;IPM&#xff09;技术&#xff0c;推动汽…

[Linux#55][网络协议] 序列化与反序列化 | TcpCalculate为例

目录 1. 理解协议 1.1 结构化数据的传输 序列化与反序列化 代码感知&#xff1a; Request 类 1. 构造函数 2. 序列化函数&#xff1a;Serialize() 3. 反序列化函数&#xff1a;DeSerialize() 补充 4. 成员变量 Response 类 1. 构造函数 2. 序列化函数&#xff1a;…

JavaWeb - 5 - 前端工程化

一.前后端分离开发 前后端混合开发 缺点&#xff1a;沟通成本高&#xff0c;分工不明确&#xff0c;不便管理&#xff0c;不便维护拓展 前后端分离开发 当前最为主流的开发模式&#xff1a;前后端分离 前后端分离开发中很重要的是API接口文档&#xff08;如&#xff1a;YApi&…

胤娲科技:谷歌DeepMind祭出蛋白质设计新AI——癌症治疗迎来曙光

在科技的浩瀚星空中&#xff0c;DeepMind的“阿尔法”家族总是能带来令人瞩目的璀璨光芒。这一次&#xff0c;它们再次以惊人的姿态&#xff0c; 将AI的触角深入到了生命的微观世界——蛋白质设计领域&#xff0c;为我们描绘了一幅未来医疗的宏伟蓝图。 想象一下&#xff0c;一…

Scrapy爬虫实战——某瓣250

# 按照我个人的习惯&#xff0c;在一些需要较多的包作为基础支撑的项目里&#xff0c;习惯使用虚拟环境&#xff0c;因为这样能极大程度的减少出现依赖冲突的问题。依赖冲突就比如A、B、C三个库&#xff0c;A和B同时依赖于C&#xff0c;但是A需要的C库版本大于N&#xff0c;而B…

VUE3配置路由(超级详细)

第一步创建vue3的项目

多版本node管理工具nvm

什么是nvm&#xff1f; 在项目开发过程中&#xff0c;使用到vue框架技术&#xff0c;需要安装node下载项目依赖&#xff0c;但经常会遇到node版本不匹配而导致无法正常下载&#xff0c;重新安装node却又很麻烦。为解决以上问题&#xff0c;nvm&#xff1a;一款node的版本管理工…

微服务-- Sentinel的使用

目录 Sentinel&#xff1a;微服务的哨兵 生态系统景观 sentinel与spring cloud Hystrix 对比 Sentinel 主要分为两部分 Sentinel安装与使用 Sentinel的控制规则 流控规则 流控规则的属性说明 新增流控规则 关联流控模式 SentinelResource注解的使用 SentinelResou…

mysql-死锁

文章目录 1、概念1.1、创建表 account1.2、id 自动创建 主键索引 primary1.3、name 没有创建索引 2、产生死锁的必要条件2.1、此时 name 没有创建 索引 3、如何处理死锁3.1、方式1&#xff1a;等待&#xff0c;直到超时&#xff08;innodb_lock_wait_timeout50s&#xff09;3.2…

GRE隧道在实际部署中的优化、局限性与弊端

GRE的其他特性 上一篇光讲解配置就花了大量的篇幅&#xff0c;还一些特性没有讲解的&#xff0c;这里在来提及下。 1、动态路由协议 在上一篇中是使用的静态路由&#xff0c;那么在动态路由协议中应该怎么配置呢&#xff1f; undoip route-static 192.168.20.0 255.255.255.0 …