一、前言
最近偶然间看到@babel/polyfill
这个包在2020年的时候,官方已经宣布废弃了。然后我们部分项目里面还是用的这个包,就想了解一下有没有什么优化空间。
看了一圈的相关文章和官方文档。发现一些新发的文章也存在信息滞后性,还有些出现了新旧版本配置混用的情况。
于是就想自己捋一下,跟着官方文档配置,一点点地去剔除对应的选项配置来进行测试。
总的来说共分为两套开发模式的推荐配置,业务应用开发
和类库开发
。
还有几个重要的版本。
- babel6、babel7.4
- core-js@2 core-js@3
本文主要是针对^babel7.4
和core-js@3
进行配置,以下配置均为实践过的,可直接使用。
二、配置详解
1. 业务应用项目
依赖
- 开发依赖
- @babel/core@7.16.0。babel的核心包,必装
- babel-loader@8.2.2。对输出js的转化,webpack中必装
- @babel/preset-env@7.16.4。babel的环境预设,业务应用和类库开发都需要装
- 生产依赖
- core-js@3。浏览器api的垫片,babel目前只处理词法环境,api都是由core-js来操作者的
- regenerator-runtime。同为垫片的一种
命令
// 业务开发中最纯粹的配置
yarn add -D @babel/core@7.16.0 babel-loader@8.2.2 @babel/preset-env@7.16.4
yarn add --save core-js@3 regenerator-runtime
babel.config.js的配置
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage', // 按需引入
modules: false, // 方便tree shaking
corejs: {
version: 3, // 使用core-js@3
proposals: true,
},
debug: true, // 日志
targets: { // 目标浏览器,和browserslist同理
chrome: '58',
ie: '11',
},
},
],
],
}
旧版本配置对比
在babel7.4之前,很多都是通过@babel/preset-env + @babel/polyfill
这种方式来配置的。甚至一些比较旧的项目中会直接引入polyfill的js<script src="**/js_polyfill"></script>
。这样做有几个问题
- 体积过大
- 污染全局环境
- 部分api不支持。比如flat、flatMap、[].includes
@babel/polyfill
的github仓库下面也提示了不推荐再使用了。
2. 类库开发
依赖
- 开发依赖
- @babel/core@7.16.0。babel的核心包,必装
- babel-loader@8.2.2。对输出js的转化,webpack中必装
- @babel/preset-env@7.16.4。babel的环境预设,业务应用和类库开发都需要装
- @babel/plugin-transform-runtime。主要是配合@babel/runtime进行使用,对局部引入的api进行自动导入,另一个作用是避免重复的helper函数引用,减少体积。
- 生产依赖
- @babel/runtime-corejs3。避免对polyfill的方式对全局进行污染。里面包含了regenerator-runtime,和其他一系列的runtime模块
babel.config.js的配置
module.exports = {
presets: [
[
'@babel/preset-env',
{
modules: false,
},
],
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
corejs: {
version: 3,
proposals: true,
},
useESModules: true,
},
],
],
}
这里需要注意的是在下面配置了@babel/plugin-transform-runtime
这个插件之后,就不要在上面的预设中配置useBuiltIns这个选项了,会报错。具体可以参考作者在这个issue下的回复。点此跳转
部分文章的错误示范
三、配置实践
因为ie中不支持的特性较多,这边我就采用ie11进行测试。
1. 测试代码
/**
* 测试Promise api
* @author waldon
* @date 2021-11-26
*/
export const promiseFn = function () {
return Promise.resolve('1')
}
/**
* 测试Map api
* @author waldon
* @date 2021-11-26
*/
export const mapFn = function () {
const map = new Map()
map.set('1', 2)
return map
}
/**
* 测试core-js3中支持的flat
* @author waldon
* @date 2021-11-26
*/
export const flatFn = function () {
return [[1], 2].flat()
}
/**
* 测试Class
* @author waldon
* @date 2021-11-26
*/
export class ClassTest {
static num = 1
}
/**
* 测试async await
* @author waldon
* @date 2021-11-26
*/
export const asyncFn = async function () {
const foo = await Promise.resolve('async')
return foo
}
2. 预设中的useBuiltIns
可选值
- false。默认值。会将所有垫片全部引入,造成体积过大,不推荐。
- entry。根据不同的环境,在入口处引入不同的core-js和regenerator-runtime/runtime
- 需在入口的js引入这两个模块
import 'core-js/stable' import 'regenerator-runtime/runtime'
- 需在入口的js引入这两个模块
- usage。按需引入。这个按需指的是,在该js文件用到的且浏览器不支持的js,同时满足这两种情况,才引入对应的api模块。
3. babel-loader的配置
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
],
},
4. 配置生效
控制台日志输出
在进行配置的时候建议开启debug: true
,方便看各个配置输出信息的差异。
ie11中的api测试
5. 部分报错解决
ie或其他低版本浏览器中出现“语法错误”
这个是因为该浏览器不支持箭头函数,只需在output
中添加配置
output: {
environment: {
arrowFunction: false, // 转换es6箭头函数为普通function
},
},
不支持Promise
- 可能是babel.config.js中的
presets
不生效。 - 检查webpack.config.js中的babel-loader中的option是否也配置了presets导致babel.config.js中的配置被覆盖
不支持flat
- 检查是否正确引用的core-js@3,因为core-js@2中是不支持flat和includes这些api的。
- 或者检查plugins中有没有配置了@babel/plugin-transform-runtime,然后预设中又配置了useBuiltIns,导致了冲突。
四、参考
- babeljs.io/docs/en/usa… babel官网
- github.com/zloirock/co… core-js作者推荐
- segmentfault.com/a/119000002… corejs3 的更新
- www.zhouzh.tech/posts/7842f… 一次 polyfill 对 babel 的思考
五、总结
实践出真知。前端的知识更新迭代太快了,有很多规范和信息在当时或许适用,但是也会被淘汰。框架类的东西尽量自己动手试一波,不然会出现很多隐藏的坑和bug。