〇、上篇文章
一、Corejs当前实现
在项目中经常会看到这种corejs代码,用来作为polyfill,使代码中的新特性能够兼容低版本的浏览器
// IE10
import 'core-js/es/map';
import 'core-js/es/set';
// IE11, IE10
import 'core-js/es/object/assign';
但是我们接手的是一个古老的项目,引入了类似上面代码块的大量的polyfill代码,许多polyfill实际上已经不再需要了,并且有些同事又爱用新的js语法来写代码,这里又缺失了一些polyfill。经常出现在browserlist中的浏览器版本被qa抓到出现了白屏现象。
所以我们需要实现一个动态的corejs插件,目标是通过package.json中的browserlist字段,获取当前需要支持的浏览器环境,生成polyfill的内容并insert到我们的入口js的顶部
二、自定义的corejs插件
我们引入core-js-builder
这个库来根据browserlist字段生成polyfill code
代码如下
// polyfill-loader.js
const builder = require('core-js-builder')
const { loadConfig } = require("browserslist")
const path = require('path')
const name = 'CorejsPolyfillPlugin'
function CorejsPolyfillPlugin() {
let entries;
this.hooks.entryOption.tap(name, (context, entry) => {
entries = Object.values(entry).reduce((result, entryItem) => {
if (entryItem.import) {
return result.concat(entryItem.import) // 支持多入口打包
}
return result
}, [])
})
this.hooks.beforeCompile.tap(name, (params) => {
// inject loader
params.normalModuleFactory.hooks.afterResolve.tap(name, (data) => {
// 注意:此处代码为webpack5版本。webpack4 版本中回调的直接就是createData, webpack5又包了一层
const { createData } = data;
if (entries.includes(createData.resource)) {
createData.loaders.push({ loader: __filename });
}
});
});
}
function PolyFillLoader(content, map, meta) {
const cb = this.async()
builder({
modules: ['core-js/actual'],
targets: loadConfig({path: path.resolve('../')}), //package.json的相对路径
format: 'esm'
}).then(corejs => {
cb(null, corejs + content, map, meta)
});
}
PolyFillLoader.CorejsPolyfillPlugin = CorejsPolyfillPlugin
module.exports = PolyFillLoader;
简述上述代码:
由于项目是个多入口打包的react项目,我们需要先找出所有entries, 通过传入package.json中browserlist
字段,让core-js-builder
生成形如下面的代码(就是代码中的corejs回调参数)
"/**\n * core-js 3.35.0\n * © 2014-2023 Denis Pushkarev (zloirock.ru)\n * license: https://github.com/zloirock/core-js/blob/v3.35.0/LICENSE\n * source: https://github.com/zloirock/core-js\n */\nimport 'core-js/modules/es.symbol.js';\nimport 'core-js/modules/es.symbol.description.js';\nimport 'core-js/modules/es.symbol.async-iterator.js';\nimport 'core-js/modules/es.symbol.has-instance.js';\nimport 'core-js/modules/es.symbol.is-concat-spreadable.js';"
三、引用自定义的corejs插件
const { CorejsPolyfillPlugin } = require('./polyfill-loader')
...
// webpack的plugin数组中push这个自定义plugin
plugins.push(CorejsPolyfillPlugin)