初衷
- webpack 虽然可以一次性降级到ES5,但会导致JS变得非常冗余,之前项目ES6包降级到ES5,JS主包增加了120%,实在是不能忍~
- vite 默认只支持ES6(chrome 80+),需要单独 legacy降级,但实际操作中会发现有不少问题,我们可以针对性解决,适配 chrome 60+内容
- 由于新项目常常会使用到 nuxt/next SSR静态化解决方案,当使用高版本也会出现类似问题
全面降级polyfill方案有很多种,babel、corejs、legacy、polyfill家族等,这里只讲针对性,代码增加幅度最小
关于低版本浏览器兼容性问题处理,针对性polyfill方案
主要解决一下内容:
- globalThis 报错
- Object.entries
- Object.assign
- includes
React 18+ /Next 方案
可以在app.ts 或者 顶部的layout.ts 配置
<html lang="zh">
<head>
{/* 内联 polyfill 脚本,确保最先执行 */}
<script
dangerouslySetInnerHTML={{
__html: `
// 为低版本浏览器提供 globalThis polyfill
(function() {
if (typeof globalThis === "undefined") {
// 更安全的 globalThis polyfill 实现
if (typeof self !== "undefined") { self.globalThis = self; }
if (typeof window !== "undefined") { window.globalThis = window; }
if (typeof global !== "undefined") { global.globalThis = global; }
}
})();
`
}}
/>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
{/* 内联额外的浏览器兼容性 polyfill */}
<script
dangerouslySetInnerHTML={{
__html: `
// 为低版本浏览器提供额外的 polyfill
(function() {
// 确保 Object.entries 可用
if (typeof Object.entries !== "function") {
Object.entries = function(obj) {
var ownProps = Object.keys(obj);
var i = ownProps.length;
var resArray = new Array(i);
while (i--) {
resArray[i] = [ownProps[i], obj[ownProps[i]]];
}
return resArray;
};
}
// 确保 Array.prototype.includes 可用
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
var len = o.length >>> 0;
if (len === 0) {
return false;
}
var n = fromIndex | 0;
var k = Math.max(n >= 0 ? n : len + n, 0);
while (k < len) {
if (o[k] === searchElement) {
return true;
}
k++;
}
return false;
};
}
// 确保 String.prototype.includes 可用
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > this.length) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
};
}
// 确保 Object.assign 可用
if (typeof Object.assign !== 'function') {
Object.assign = function(target) {
if (target == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) {
for (var nextKey in nextSource) {
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};
}
})();
`
}}
/>
</head>
<body>
</body>
</html>
VUE3/nuxt3 方案
可以在nuxt.config.ts 或者 vite.config.ts 中添加
script: [
// 添加 Promise.allSettled polyfill
{
innerHTML: `
if (!Promise.allSettled) {
const rejectHandler = reason => ({ status: 'rejected', reason });
const resolveHandler = value => ({ status: 'fulfilled', value });
Promise.allSettled = function (promises) {
const convertedPromises = promises.map(p => Promise.resolve(p).then(resolveHandler, rejectHandler));
return Promise.all(convertedPromises);
};
}
`,
type: "text/javascript",
},
// 添加 globalThis polyfill
{
innerHTML: `
if (typeof globalThis === 'undefined') {
window.globalThis = window;
}
`,
type: "text/javascript",
},
],