背景
在 ie 环境下,有一些高级的 api 可能不存在,比如 promise,如下:
/** ./src/index.js **/
const P = new Promise((resolve, reject)=>{});
打包过后,我们得到以下的结果:
我们发现 new Promise 并没有不转化,如果在 ie 环境下就会报错了。
解决方案(三种)
这边有几种方案可选:
- @babel/preset-env 方案(推荐)
- @babel/polyfill 方案
@babel/plugin-transform-runtime 方案
@babel/preset-env 方案
我们需要通过之前使用的 @babel/preset-env 来在我们的环境中构建一个 Promise。除此之外我们还需要用到 core-js ,Promise 的代码就被存放在 core-js 中。
安装
安装 core-js 包并且它是运行时依赖。
yarn add core-js@3
webpack 配置
给 @babel/preset-env 穿参数时,presets 的值改成数组的数组,数组元素的第一个为包的名字,第二个参数为 包的参数,如下:
参数配置如下:useBuiltIns 这个参数代表了 @preset-env 如何处理polyfills,它有三个参数:false,“entry” ,“usage”。其默认值为false。当取值为false的时候,polyfill会被全部引入到代码中。所以,一般不会取false;剩下的两个配置要和corejs搭配使用,当取值为当取值为“entry”或”usage”的时候,须声明corejs的版本并安装corejs库,如果不安装的话,执行babel命令时会弹出提示。
当取值为”entry”时,需要在项目的入口文件处手动引入”core-js”,执行babel命令时根据配置项的targets目标环境找出需要的polyfill进行部分引入。当取值为”usage”的时,除了会考虑目标环境缺失的API以外,同时还会关注我们项目代码里使用到的ES6特性。只有我们使用到的ES6特性API在目标环境缺失的时候,才会进行引入。所以在项目中,一般是采用”usage”的配置。因此在这里可以对”entry”和“usage”的区别做一个总结,主要有以下两点:
采用entry配置时,须在入口文件处手动引入 core-js,usage不需要
import 'core-js'
采用entry配置时,会将环境中缺失的api全部引入,而usage只会引入项目中用到api
所以这边我们采用 usage 模式,同时安装 core-js,指定 core-js 的版本,如下:
/** ./webpack.config.js **/
let path = require('path');
//...
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname, './src'),
use:[
{
loader: 'babel-loader',
options: {
//帮你转化高版本的api语法
//不支持在 提案中的方法 stage-x ,例如装饰器。
//不使用这种方法的话,可以在代码中引用 @babel/polyfill
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',// 只转化使用的 api
corejs: { version: 3 }
}
]
],
plugins: ['@babel/plugin-transform-runtime']
}
}
]
}
]
}
//...
}
//...
最终打包结果
再看我们的打包文件,如下:
我们会发现多了很多代码,这就是在新构建的 Promise,这样在 ie 环境下也能够使用 Promise 了。
@babel/polyfill 方案
@babel/plugin-transform-runtime 方案
@babel/plugin-transform-runtime 之前我们也用到过了,用来提取公共代码,这边解决高级 api 的问题,也可以用到这个包,配置方法如下:
安装依赖包
刚才的 @babel/preset-env 依赖 core-js 包。而 @babel/plugin-transform-runtime 不需要依赖这个包,但是相似的依赖另外一个包 @babel/runtime-corejs3 ,也是 corejs 的包。
yarn add @babel/runtime-corejs3
webpack 配置
//...
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname, './src'),
use:[
{
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env',{
//useBuiltIns: 'usage',
//corejs: { version: 3 }
}]],
plugins: [['@babel/plugin-transform-runtime', {
"absoluteRuntime": false,
"corejs": 3,
"helpers": true,
"regenerator": true,
"version": "7.0.0-beta.0"
}]]
}
}
]
},
]
}
//...
}
//...
最终打包结果
补充
- 除了 Promise 外,还支持字符串、数组的 includes 等其他方法,如下:
因为使用了 usage,所以必须在代码中用到 includes 才会被打包进来,如下: