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 版本中被标记为已废弃。 |
Babel | 是 | Babel 的文档推荐设置targets选项(使用 Browserslist),但如果未指定,它将转译所有代码为 ES5。 |
webpack | 否 | 默认情况下,webpack 不会转译任何代码。大多数 webpack 用户包括babel-loader,而 webpack 的使用示例建议设置targets: "defaults" 。 |
TypeScript (tsc) | 是 | TypeScript 的默认target选项是 ES5。 |
Next.js | 否 | Next.js使用 Babel 进行转译,默认设置一个 Browserslist 配置,目标是"现代浏览器"(即支持 ES 模块的浏览器)。 |
esbuild | 否 | esbuild默认不进行转译。你可以设置自定义目标以启用转译,但 ES5 不支持作为转译目标。 |
Vite | 否 | Vite 使用 esbuild,默认设置自定义目标为"现代浏览器"(即支持 ES 模块的浏览器)。如果需要支持旧版浏览器,Vite 允许用户安装一个插件。 |
Rollup | 否 | Rollup 默认不进行转译。许多 Rollup 用户安装@rollup/plugin-babel,在这种情况下使用 Babel 的默认配置。 |
Parcel | 否 | Parcel自动应用差异化服务,并具有可自定义的目标。 |
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.js | 是 | async/await,箭头函数,展开运算符,解构赋值 |
d3 | 是 | 箭头函数,展开运算符,解构赋值 |
Framer-motion | 是 | 箭头函数,展开运算符,解构赋值 |
greensock | 否 | 仅 ES5 |
dayjs | 否 | 仅 ES5 |
Zod | 是 | async/await,箭头函数,展开运算符,解构赋值 |
RxJS | 是 | 箭头函数 |
immer | 是 | 箭头函数,展开运算符,解构赋值 |
luxon | 是 | async/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.module
或package.exports
字段。在这些情况下,我只查看了使用默认配置时打包器拉取的脚本版本(因为这是大多数人使用的),而今天的打包器默认使用package.module
或package.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+语法的代码,实际上只有两种可能的解释:
- 该网站不需要支持 ES5 浏览器,但他们的一些依赖项转译为 ES5,因此 ES5 代码出现在他们的输出中。
- 该网站打算支持 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
相关文章:
ES5 在 Web 上的现状
最后一个支持 ES5 的浏览器 IE 11 在 2022 年被微软停止支持,那么今天 Web 上的 ES5 现状如何?在构建生产代码时,Web 开发者的最佳实践是什么? 本文将通过数据来回答这些问题,并基于这些数据为网站开发者和库作者提供一…...
人话学Python-循环语句
一:while语句 while语句的组成由判断条件和执行语句组成。当满足条件时会不断执行后续语句,然后再循环执行的语句结束之后再次回到条件判断,如此循环。 pos 0 ans 0 while pos < 6:ans pos * 4pos 1 print(ans)>>>84"&…...

初识模版!!
初识模版 1.泛型编程1.1 如何实现一个交换函数呢(使得所有数据都可以交换)?1.2 那可以不可以让编译器根据不同的类型利用该模子来生成代码呢? 2.模版类型2.1 模版概念2.2 函数模版的原理2.3 函数模板的实例化2.4 模板参数的匹配原…...
算法之数学--hash算法 2021-03-11(未完待续)
1.hash算法 刷出一道墙 题目描述 Time Limit: 2000 ms Memory Limit: 256 mb 在一面很长的墙壁上,工人们用不同的油漆去刷墙,然而可能有些地方刷过以后觉得不好看,他们会重新刷一下。有些部分因为重复刷了很多次覆盖了很多层油漆ÿ…...

DHCP工作原理
在学习之前先提出几个问题:什么是DHCP?为什么要使用DHCP?在什么场景中使用DHCP?DHCP报文的目的IP和目的MAC是多少?DHCP报文是基于UDP还是基于TCP?DHCP服务器返回的报文中都包含什么信息? DHCP&a…...

服务发现和代理实例的自动更新
☞ 返回总目录 1.服务发现的两种方式 StartFindService 方法 这是一个在后台启动的连续 “FindService” 活动,当服务实例的可用性发生变化时,会通过回调通知调用者。 它返回一个FindServiceHandle,可通过调用StopFindService来停止正在进行…...

Redis的三种持久化方法详解
Redis持久化机制详解 | JavaGuide Redis 不同于 Memcached 的很重要一点就是,Redis 支持持久化,而且支持 3 种持久化方式: 快照(snapshotting,RDB)只追加文件(append-only file, AOF)RDB 和 A…...

OpenAI GPT o1技术报告阅读(5)-安全性对齐以及思维链等的综合评估与思考
✨继续阅读报告:使用大模型来学习推理(Reason) 原文链接:https://openai.com/index/learning-to-reason-with-llms/ 编码 我们训练了一个模型,在2024年国际信息学奥林匹克竞赛(IOI)中得分213分,排名在第…...

nodejs 012:Babel(巴别塔)语言转换与代码兼容
这里写目录标题 安装 Babel配置presets配置:常见的 Babel Presetsplugins配置:以 plugin-transform-class-properties 的类中属性为例index.jsx Babel 是一个独立的 JavaScript 编译器,主要用于将现代 JavaScript 代码转换为旧版本的 JavaScr…...

时间安全精细化管理平台存在未授权访问漏洞
漏洞描述 登录--时间&安全精细化管理平台存在未授权访问漏洞导致与员工信息泄露 FOFA: body"登录--时间&安全精细化管理平台" 漏洞复现 POC: IP/acc/_checkinoutlog_/...

软件卸载工具(windows系统)-geek
有时候软件卸载会很麻烦,使用geek会比较方便。但是针对一些特别大的软件,geek也好像会稍微费点劲(比如MATLAB2022A),不过针对一般常规软件的卸载,geek就可以有效地完全卸载了,使用方法也很简单,…...
第三篇 第14篇 工程计价依据
第三篇 工程计价 第14篇 工程计价依据 14.1 工程造价管理标准体系与工程定额体系 14.1.1 工程造价管理标准体系 1.基础标准 工程造价术语标准建筑工程计价设备材料划分标准有关建设工程费用构成通则。建设工程费用构成和分类是工程计价最重要的基础工作。 2.管理规范 建筑…...

java 异常-Exception
异常的概念 Java 语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常) 执行过程中所发生的异常事件可分为两大类 (1)Error(错误):Java 虚…...

爬虫逆向学习(六):补环境过某数四代
声明:本篇文章内容是整理并分享在学习网上各位大佬的优秀知识后的实战与踩坑记录 引用博客: https://blog.csdn.net/shayuchaor/article/details/103629294 https://blog.csdn.net/qq_36291294/article/details/128600583 https://blog.csdn.net/weixin_…...

IO流体系(FiletOutputStream)
书写步骤: 1.创建字节输出流对象 细节1:参数是字符串表示的路径或者是File对象都是可以的 细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。 细节3:如果文件已经存在,则会清空文件 2.写数据 细节:write方法的参数…...

网络设备登录——《路由与交换技术》实验报告
目录 一、实验目的 二、实验设备和环境 三、实验记录 1.通过 Console 登录 步骤1:连接配置电缆。 步骤2:启动PC,运行超级终端。 步骤3:进入Console 配置界面 2.通过 Telnet 登录 步骤1:通过 Console 接口配置 Telnet 用户。 步骤2:配置 super 口令 步骤3:配置登录欢迎…...

CSS——网格布局(display: grid)之下篇
CSS——网格布局(display: grid)之下篇 前面我们介绍了网格布局的基础的创建以及一些比较基础的属性,下面我们将介绍网格布局的剩余部分,还将结合实例来进行细致的讲解(图文并茂,生动形象有内涵࿰…...
低势期操作
《周易》讲事务发展有六个阶段: 第一阶段:潜龙勿用。 第二阶段:见龙在田。 第三阶段:终日乾乾。 第四阶段:或跃在渊。 第五阶段:飞龙在天。 第六阶段:亢龙有悔。 现在大环境不好ÿ…...
IMS 呼叫流程(详细)
目录 业务模型 典型组网如图1所示 信令流程 具体的语音流程如图2所示 主叫信令面流程 01:UE_A->P-CSCF/ATCF 02:P-CSCF/ATCF_A->PCRF_A 03:PCRF_A->PCSCF/ATCF_A 04:P-CSCF/ATCF_A 处理(把S-CSCF加到Route) 05:S-CSCF_A->MMTel AS/SCC AS_A 06:MM…...
系统架构设计师:系统架构设计
简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师:系统架构设计前言软件架构设计与生命周期SA 实现阶段主要关注的内容A…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...