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.mzph.cn/pingmian/54384.shtml

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

相关文章

如何有效检测住宅IP真伪?

在当今的互联网时代,住宅IP(即家庭用户通过宽带服务提供商获得的IP地址)在跨境电商、广告投放、网络安全等多个领域扮演着重要角色。然而,随着网络环境的复杂化和欺诈行为的增多,如何有效检测和辨别住宅IP的真伪成为了…

Spring:统一结果私有属性造成的前端无法访问异常报错问题

用户未填写任何评价 1.问题复现 (1)看一段代码 controller: import lombok.extern.slf4j.Slf4j; import org.ljy.testdemo.common.Result; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.w…

Centos中关闭swap分区,关闭内存交换

概述: Swap 分区是 Linux 系统中扩展物理内存的一种机制。Swap的主要功能是当全部的RAM被占用并需要更多内存时,用磁盘空间代理RAM内存。Swap对虚拟化技术资源损耗非常大,一般虚拟化是不允许开启交换空间的,如果不关闭Swap&…

【Linux课程学习】make/Makefile:Linux项目自动化构建工具

🎁个人主页:我们的五年 🔍系列专栏:Linux课程学习 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 🍉一.make/Makefile的理解: …

关于STM32项目面试题02:ADC与DAC篇(输入部分NTC、AV:0-5V、AI:4-20mA和DAC的两个引脚)

博客的风格是:答案一定不能在问题的后面,要自己想、自己背;回答都是最精简、最精简、最精简,可能就几个字,你要自己自信的展开。 面试官01:什么是模数转换/ADC?说说模数转换的流程? …

基于SpringBoot+Vue+MySQL的手机销售管理系统

系统展示 用户前台界面 管理员后台界面 商家后台界面 系统背景 随着智能手机的普及和市场竞争的日益激烈,手机销售行业面临着前所未有的挑战与机遇。传统的手工记录和简单的电子表格管理方式已难以满足现代手机销售业务的需求,销售数据的混乱和管理效率低…

技术成神之路:设计模式(十四)享元模式

介绍 享元模式(Flyweight Pattern)是一种结构性设计模式,旨在通过共享对象来有效地支持大量细粒度的对象。 1.定义 享元模式通过将对象状态分为内部状态(可以共享)和外部状态(不可共享)&#xf…

C语言-文件操作-一些我想到的、见到的奇怪的问题

博客主页:【夜泉_ly】 本文专栏:【C语言】 欢迎点赞👍收藏⭐关注❤️ C语言-文件操作-一些我想到的、见到的奇怪的问题 前言1.在不关闭文件的情况下,连续多次调用 fopen() 打开同一个文件,会发生什么?1.1过…

Cursor火出圈,未来程序员还有出路吗?

大家好,我是凡人。 今天我表弟家邻居的阿姨,托他问问我目前程序员还有前景吗,希望我根据十几年的经验给出点建议,看看程序员这条路未来能不能走。 一下子不知道该怎么回复他了,如果是三年前问我,肯定毫不…

【React】React18.2.0核心源码解读

前言 本文使用 React18.2.0 的源码,如果想回退到某一版本执行git checkout tags/v18.2.0即可。如果打开源码发现js文件报ts类型错误请看本人另一篇文章:VsCode查看React源码全是类型报错如何解决。 阅读源码的过程: 下载源码 观察 package…

解决【WVP服务+ZLMediaKit媒体服务】加入海康摄像头后,能发现设备,播放/点播失败,提示推流超时!

环境介绍 每人搭建的环境不一样,情况不一样,但是原因都是下面几种: wvp配置不当网络端口未放开网络不通 我搭建的环境: WVP服务:windows下,用idea运行的源码 ZLM服务:虚拟机里 问题描述 1.…

【人工智能学习笔记】5 计算机视觉基础

计算机视觉概述 定义:计算机视觉(Computer Vision)是一门研究如何使机器“看”的科学,也可以看作是研究如何使人工系统从图像活多维数据中“感知”的科学终极目标:计算机视觉成为机器认知世界的基础,终极目…

superset 解决在 mac 电脑上发送 slack 通知的问题

参考文档: https://superset.apache.org/docs/configuration/alerts-reports/ 核心配置: FROM apache/superset:3.1.0USER rootRUN apt-get update && \apt-get install --no-install-recommends -y firefox-esrENV GECKODRIVER_VERSION0.29.0 RUN wget -q https://g…

【高级篇】ENC编码器如何挂载Windows共享目录进行录像

【高级篇】ENC编码器如何挂载Windows共享目录进行录像 Windows共享目录前提条件1、打开控制面板,点击 程序 菜单2、点击 启用或关闭Windows功能 菜单3、如下图,勾选SMB1.0/CIFS文件共享支持,并点击确认按钮,然后根据提示重启电脑 创建共享目录…

如何利用Samba跨平台分享Ubuntu文件夹

1.安装Samba 终端输入sudo apt install samba 2.配置Samba 终端输入sudo vim /etc/samba/smb.conf 打开配置文件 滑动文件到最底下 输入以下内容 [Share] # 要共享的文件夹路径 path /home/xxx/sambashare read only no browsable yes编辑完成后按一下Esc按键后输入:wq回…

ABAP-Swagger 一种公开 ABAP REST 服务的方法

ABAP-Swagger An approach to expose ABAP REST services 一种公开 ABAP REST 服务的方法 Usage 1: develop a class in ABAP with public methods 2: implement interface ZIF_SWAG_HANDLER, and register the public methods(example method zif_swag_handler~meta) 3: …

Docker 以外置数据库方式部署禅道

2.安装步骤 2.1.参考资料 禅道官网文档: https://www.zentao.net/book/zentaopms/docker-1111.html https://www.zentao.net/book/zentaopms/405.html 2.2.详细步骤 ssh 登录服务器创建目录 /opt/zentao /opt/zentao/data /opt/zentao/db cd /opt mkdir zentao mkdir zentao…

开源免费的NAS系统-TrueNAS CORE上创建CentOS7虚拟机

目录 文章目录 目录1、说明2、准备工作2.1、准备安装镜像2.1、创建用户2.2、开启 ssh 服务2.3、设置用户权限2.4、上传系统镜像2.5、 添加虚拟机 3、开始安装系统3.1、启动虚拟机3.2、选择语言3.3、配置网络3.4、设置 root 密码3.5、删除光驱3.6、重启虚拟机3.7、使用 ssh 连接…

C++ | Leetcode C++题解之第414题第三大的数

题目&#xff1a; 题解&#xff1a; class Solution { public:int thirdMax(vector<int> &nums) {int *a nullptr, *b nullptr, *c nullptr;for (int &num : nums) {if (a nullptr || num > *a) {c b;b a;a &num;} else if (*a > num &&am…

【Python】练习:控制语句(二)第4关

第4关&#xff1a;控制结构综合实训 第一题第二题&#xff08;※&#xff09;第三题&#xff08;※&#xff09;第四题&#xff08;※&#xff09;第五题&#xff08;※&#xff09;第六题&#xff08;※&#xff09; 第一题 #第一题def rankHurricane(velocity):#请在下面编写…