Skip to content

babel

什么是 Babel?

  • Babel 是一个 JS 编译器,通过 Babel 我们可以把按最新标准编写的 JS 代码向下编译成兼容浏览器或其他环境的通用版本。
  • 虽然 Babel 开箱即用,但是如果不做任何配置,输入原始代码,则会输出同样的原始代码。如果想要做一些实际工作,需要添加插件(plugins)。一个个手动引入需要的插件过于繁琐,所以通常会使用官方提供的预设(presets),预设是插件的集合。 官方提供的预设:@babel/preset-env

Babel 转译代码,会将代码分成两部分

  • syntax(语法):箭头函数、let、const、展开运算符等
  • api:Promise、includes、map等
  • Babel 默认不转换 syntax 和 api ,使用 @babel/preset-env 或 babel-runtime 后转换 syntax,但不会转换 api 。需要使用垫片(polyfill)转换 api,polyfill 可以让新的内置函数、实例方法等在低版本环境中也可以使用。

官方给出了两种 polyfill 方案

  • babel-polyfill:会污染全局适合在业务项目中使用。(Babel7.4.0版本开始,babel/polyfill 已经被废弃,推荐直接使用core-js)
  • babel-runtime:不污染全局适合在组件或类库项目中使用。

几种配置区别

1. 不做任何配置

会发现输出的 lib/index.js 文件,与编译之前没有区别,输出了原始代码。 在根目录添加文件:

babel.config.json(Babel配置文件) .browserslistrc(声明了一段浏览器集合,根据这段集合描述,针对性的输出兼容性代码) 看看使用了配置和浏览器策略之后,会有哪些改变。

2. @babel/preset-env

  • 只转换syntax(class,typeof,箭头函数),不转换api(map,includes)
  • syntax的转换策略会根据浏览器策略(.browserslistrc文件的配置)改变

3. @babel/preset-env + core-js@3

  • 转换 syntax 和 api。
  • syntax 和 api 的转换策略会根据浏览器策略改变。
  • polyfill 从core-js@3 引入。
json
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "corejs": 3,
                "useBuiltIns": "usage"
            }
        ]
    ]
}
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "corejs": 3,
                "useBuiltIns": "usage"
            }
        ]
    ]
}

介绍一下配置项 useBuiltIns :默认为 false,可以使用的值有 usage 和 entry

  • usage:不需要手动 import '@babel/polyfill',会根据 browserlist + 业务代码使用到的新 API 按需自动加上 polyfill
  • entry:需要手动 import '@babel/polyfill',根据 browserlist 中浏览器版本的支持,将 polyfill 拆分引入浏览器不支持的 polyfill。这样会导致实际用不到的 polyfill 也会被打包到输出文件,导致文件比较大。
  • false:不启用 polyfill,如果 import '@babel/polyfill', 会无视 browserlist 将所有的 polyfill 加载进来。
  • 新版本的 Babel,会提示直接引入 core-js 或者 regenerator-runtime/runtime 来代替@babel/polyfill。

4.@babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime

  • api转换会根据策略改变。
  • syntax转换会根据策略改变。
@babel/runtime 和 @babel/plugin-transform-runtime 的关系:
  • plugin-transform-runtime 用于编译时转译代码,真正的polyfill在代码运行时从babel/runtime里引入,所以plugin-transform-runtime 需要安装在开发环境,而babel/runtime安装在生产环境。
@babel/runtime 和 @babel/runtime-corejs3:
  • @babel/runtime包含:helpers、regenerator-runtime。只能处理语法。
  • @babel/runtime-corejs3包含:helpers、regenerator-runtime、core-js@3。引入core-js@3处理api。

Babel 在每个需要转换的代码前面都会插入一些 helpers 代码,这可能会导致多个文件都会有重复的 helpers 代码。@babel/plugin-transform-runtime 的 helpers: true 选项就可以把这些代码抽离出来。

json
{
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3,
                "helpers": true,
                "regenerator": false
            }
        ]
    ],
    "presets": [
        [
            "@babel/preset-env"
        ]
    ]
}
{
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3,
                "helpers": true,
                "regenerator": false
            }
        ]
    ],
    "presets": [
        [
            "@babel/preset-env"
        ]
    ]
}

5. 组合使用@babel/preset-env + core-js@3 + @babel/plugin-transform-runtime + @babel/runtime-corejs3

  • core-js 设置转译api, runtime 设置 false 不转译api。
  • runtime 转换了语法,没有转 api,core-js 转了api。
  • runtime 提取 helper 代码,减少重复代码,core-js 使用最新版本按需引入。
  • 体积最小

6. 组合使用@babel/preset-env + core-js@3 + @babel/plugin-transform-runtime + @babel/runtime-corejs3,core-js和runtime都设置转译api

  • runtime转了语法和api,两者不会重复转译,输出结果与配置4一致。
json
{
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3,
                "helpers": true,
                "regenerator": false
            }
        ]
    ],
    "presets": [
        [
            "@babel/preset-env",
            {
                "corejs": 3,
                "useBuiltIns": "usage"
            }
        ]
    ]
}
{
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3,
                "helpers": true,
                "regenerator": false
            }
        ]
    ],
    "presets": [
        [
            "@babel/preset-env",
            {
                "corejs": 3,
                "useBuiltIns": "usage"
            }
        ]
    ]
}

总结:

  • 个人测试的编译后体积最小的代码是配置5:使用 core-js 的 useBuiltIns 设置按需引入 polyfill 结合 @babel/plugin-transform-runtime 提取重复代码的 helper 代码。
  • 官方建议的使用方式是:根据使用场景,useBuiltIns 的 polyfill 全局范围添加,@babel/plugin-transform-runtime 的 polyfill 非全局范围添加,采用一种配置即可。

Released under the MIT License.