最新的babel配置及实践

1,509 阅读4分钟

一、前言

最近偶然间看到@babel/polyfill这个包在2020年的时候,官方已经宣布废弃了。然后我们部分项目里面还是用的这个包,就想了解一下有没有什么优化空间。

看了一圈的相关文章和官方文档。发现一些新发的文章也存在信息滞后性,还有些出现了新旧版本配置混用的情况。
于是就想自己捋一下,跟着官方文档配置,一点点地去剔除对应的选项配置来进行测试。 总的来说共分为两套开发模式的推荐配置,业务应用开发类库开发
还有几个重要的版本。

  • babel6、babel7.4
  • core-js@2 core-js@3

本文主要是针对^babel7.4core-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'
      
  • 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,导致了冲突。

四、参考

五、总结

实践出真知。前端的知识更新迭代太快了,有很多规范和信息在当时或许适用,但是也会被淘汰。框架类的东西尽量自己动手试一波,不然会出现很多隐藏的坑和bug。