今天发现一个Object.hasOwn
的API在低版本浏览器中无法兼容的问题。
考虑了如下解决方案,一个个说
1. 回退之前的hasOwnProperty
旧版本API。
治标不治本,还有其他的兼容API没有处理。
2. 引入polyfill
但是我以为next原本就配置好了polyfill的预设,为什么还会这样呢,可能是next的预设兼容的浏览器版本还是没有覆盖那个旧的版本。
说起来其实我对polyfill只知道babel做了处理,但却不知道具体操作,因此调研了一下:
参考:
- polyfill使用:https://juejin.cn/post/6923912946238095368?from=search-suggest
- next中预设polyfill的配置优化:https://juejin.cn/post/7077380997133631495
下面的文章顺序也是先讲怎么使用polyfill
和它的规则,后面再说next里怎么配置的。
2.1 @babel/polyfill
一个早期方案,现已不再使用。会导致node_modules依赖的三方库的代码也被改写。
2.2 @babel/plugin-transform-runtime+core-js@3
配置如下
yarn add @babel/plugin-transform-runtime
yarn add core-js@"^3"
yarn add @babel/runtime-corejs3
module.exports = {
presets: [
[
'@babel/preset-env'
],
],
plugins: [
[
"@babel/plugin-transform-runtime",
{
corejs: 3,
}
]
]
};
2.3 @babel/preset-env + usage or entry
usage和entry比较好理解,entry默认会把整个core-js打包进最终代码,而usage会分析你使用到的代码
// 首先在打包入口的index.js处引入垫片
import 'core-js/stable'
import "regenerator-runtime/runtime";
// 然后配置预设
module.exports = {
presets: [
[
'@babel/preset-env',{
useBuiltIns: 'entry',
corejs: 3,
},
],
],
};
useBuiltIns:entry or usage
如果是entry
,可以在打包后的输出chunk代码中看到引入了polyfill的所有方法,随意搜索一个ES6+的API都能在打包后的代码中找到,同时打包未压缩前的体积非常大。
因此才引入了usage
的配置。
usage
可以根据当前打包的代码中API引入对应的polyfill API。不过只针对ES modules规范,如果依赖是CJS规范的话,依赖中的代码若需要polyfill无法被usage检测出来,这样就把风险转移给了第三方代码库的自兼容上。
@babel/preset-env + useBuiltIns:usage + @babel/plugin-transform-runtime+core-js@3
但是@babel/preset-env
会引入重复的内联函数(“助手函数”,具体看参考文章中的截图),为了能提取这些重复方法,还需要@babel/plugin-transform-runtime来解决,最终的设置如下:
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: 3,
},
],
],
plugins: [
[
"@babel/plugin-transform-runtime",
{
// vue-cli的配置,可以避免重复注入相同兼容API
// polyfills are injected by preset-env & polyfillsPlugin, so no need to add them again
corejs: false,
version: require('@babel/runtime-corejs3/package.json').version,
}
]
]
};
3. Next中的polyfill处理
参考文章:
next中预设polyfill的配置优化,上面2写过一遍这个链接的。
什么是预设中的browserslist>0.25%和"last 2 versions" ?
我找了一下github我的这个12.0.7版本的babel预设,看起来是没有配置什么useBuiltIns
和browserList,应该都是用的默认配置。
参考博主目前是采用了主动给第三方node_modules依赖增加该API的 polyfill来解决问题。
- webpack中主动增加打包入口,增加一个polyfill垫片的打包文件。
config.entry = async () => {
const entries = await originalEntry();
if (entries['main.js']) {
entries['main.js'].unshift('./static/js/polyfills-legacy.js');
}
return entries;
};
- 那个polyfill垫片文件
./static/js/polyfills-legacy.js
// React
import 'core-js/es6/map';
import 'core-js/es6/set';
// Next.js
import 'core-js/fn/string/starts-with';
4. 调试方案:
可以看这里面推荐的:https://zhuanlan.zhihu.com/p/4030685403
-
如果兼容的版本范围要求不是很高并且时间不是特别长,
可以用这个网站,免费的:https://www.browserling.com/#pricing -
收费的有browserstack等。