都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?

最近在Code Review里,我看到一个新同学在一个vite.config.js里,习惯性地加上了@vitejs/plugin-legacy,用来支持旧版浏览器。

我问他:"我们的目标用户里,真的还有人用那些浏览器吗?"

他愣了一下,说:"不知道,但加上总比不加好吧?万一呢?"

这个回答,让我陷入了沉思。"加上总比不加好",这句听起来非常正确的话,真的是对的吗?

要做好兼容性,这句话,就像一句咒语,刻在了我们这代前端工程师的骨子里。从当年大战IE6,到后来ES6普及时,为各种新语法打补丁,polyfillbabel就是我们的救命稻草。在入口文件顶部写下一行import 'core-js/stable',仿佛是一种兼容标准。

但现在都2025年了,IE早已入土为安,主流浏览器都已现代化。我越来越觉得,盲目地、无差别地为项目引入全量polyfill,已经从一个最佳实践,变成了一种技术债。


过度追求兼容性,让我们付出了哪些代价?

我们先来算一笔账。当我们无脑地引入一个完整的polyfill方案时,我们付出的代价是什么?

打包体积的代价

这是最直接的代价,最终由我们的用户来买单。

我随手在一个Vite + Vue 3的项目里,

javascirpt 复制代码
import 'core-js/stable'
import 'regenerator-runtime/runtime'

只是import 'core-js/stable',然后用rollup-plugin-visualizer分析一下打包体积:

一个完整的core-js,会给你的JS包增加几百KB的大小,而且占用整个项目78%的代码!!!这些代码,对于你项目中99%的、使用现代浏览器的用户来说,是完全用不上、不会被执行的死代码。他们却要为这部分代码,付出实实在在的流量和加载时间。

运行时性能的代价

Polyfill不只是下载下来就完事了,它还需要在浏览器里被解析和执行。虽然这个开销对于单个polyfill来说很小,但当一个庞大的polyfill集合在你的应用启动时就开始注入和执行,这无疑会增加主线程的负担,对首次可交互时间(TTI)和总阻塞时间(TBT)产生负面影响。


都2025年了,我们到底在兼容什么?

既然代价如此之大,那我们回头看看,我们如此大费周章,到底是在兼容什么?

首先,我们必须明确一点:IE已经死了!

在2025年,任何还在要求兼容IE的项目,要么是预算给够的古董维护项目,要么就应该重新评估它的商业价值。对于绝大多数面向公众的互联网产品,我们可以、也应该,大胆地和IE说再见。

其次,主流浏览器都是常青的。

Chrome, Firefox, Edge都具备自动更新能力,这意味着你绝大部分的用户,使用的都是最新或次新的浏览器版本,它们对ES2020+的特性支持都非常好。

那么,我们现在做兼容,主要目标是谁?

答案是:那些无法更新操作系统的、旧款设备上的浏览器。

所以,问题的关键就变成了:你的用户里,到底有多少人在用这些过时的浏览器?

根据 Statcounter的数据 ,全球浏览器市场份额👇:

Chrome 仍然是全球用户的首选,其次是 Safari,成为第二受欢迎的选择。Edge、Firefox 和 Samsung Internet 也占有相当大的份额,而 Opera 和其他小众浏览器则占到只有 5% 的市场份额

作为技术组长,我要求我们团队做任何关于兼容性的决策前,必须拿数据说话。打开你们自己项目的统计后台看一看,那个小于1%的others,真的值得我们让99%的用户去承担性能代价吗?


我的一些建议,Polyfill使用策略

我不是在鼓吹完全放弃兼容性,而是主张一种更智能、更精准、代价更小的策略。

明确定义 - 你的浏览器支持基线

和你的团队、产品经理一起,根据你的用户数据,明确定义出你们产品需要支持的最低浏览器版本。比如,我们可以定义为:"所有主流浏览器最近两个大版本"。把它写进团队的开发规范文档里。这是一个契约,也是我们后续做决策的依据。

放弃全量引入,按需分析

请立刻从你的项目入口文件里,删掉 import 'core-js/stable'或import 'babel-polyfill' 这种一刀🔪切的写法。

我们应该完全信赖构建工具的静态分析能力。比如,在babel.config.js里这样配置:

JavaScript 复制代码
presets: [
  ['@babel/preset-env', {
    useBuiltIns: 'usage', // 关键配置
    corejs: 3
  }]
]

useBuiltIns: 'usage' 这个选项,意味着Babel会自动检测你的代码,只把你代码中用到了的 、并且在你目标浏览器中不支持的 那些新特性,才引入对应的polyfill。这能极大地减小polyfill的体积。

考虑使用Polyfill后端服务

对于一些大型应用,可以考虑使用Polyfill服务(比如polyfill.io的自建替代品,因为官方服务曾出现过稳定性问题, 现在好像都无法访问了😒)。

它的原理是:服务器根据请求的User-Agent头,判断出用户的浏览器版本,然后只下发这个浏览器所需要的polyfill脚本。这是最高效、最精准的方案。

拥抱渐进增强,接受优雅降级

(这是一个说烂了的话题, 说白了就是 摆烂🤔)

对于一些非核心的、锦上添花的新API(比如View Transitions API),我们可以不提供polyfill。在支持的浏览器上,用户能体验到炫酷的页面切换动画;在不支持的浏览器上,它就是一个普通的页面跳转。

不是所有功能,都值得我们用增加全体用户性能负担的方式,去强行兼容。


作为开发者,我们的职责不只是实现功能,还包括控制我们产品的开发成本------这其中就包括了用户需要付出的加载成本。

为那1%的、甚至在你的用户数据里根本不存在的旧浏览器用户,让99%的现代浏览器用户去承担额外的加载负担,在2025年,这已经是一笔不划算的买卖了。

是时候检查一下你的项目了。打开你的打包分析报告,看看core-js占了多大。

然后,问问你自己:"这些代码,真的有必要吗?"

欢迎大家讨论😎

相关推荐
yangcode1 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu1 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu1 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript
LuckySusu1 小时前
【js篇】深入理解 JavaScript 作用域与作用域链
前端·javascript
LuckySusu1 小时前
【js篇】call() 与 apply()深度对比
前端·javascript
LuckySusu2 小时前
【js篇】addEventListener()方法的参数和使用
前端·javascript
该用户已不存在2 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net
LuckySusu2 小时前
【js篇】深入理解 JavaScript 原型与原型链
前端·javascript
文心快码BaiduComate2 小时前
文心快码入选2025服贸会“数智影响力”先锋案例
前端·后端·程序员