blog icon indicating copy to clipboard operation
blog copied to clipboard

@babel/preset-env与@babel/plugin-transform-runtime

Open chenlong-io opened this issue 5 years ago • 0 comments

babel 在转译时,会将源码分为两个部分来处理,分别是: syntax 和 api

  • syntax:类似对象展开、optional chain、let、const 等语法
  • api:类似数组的 includes 等函数、方法

@babel/preset-env

{
    "presets": [ ["@babel/preset-env"] ]
}

preset-env可以使用最新的 JavaScript Api ,它是许多 preset 的集合(es2015+),通过配置来智能使用 JavaScript。

但随着 ECMA 的发展会一直更新和增加里面的内容,比如今年(2021年)它包含的预设由:es2020、es2019、... es2015。到了明年,它的 preset 可能就多包含一个 es2021

默认情况下,preset-env 跟 babel-preset-latest 是等同的;

在发中,如果需要支持特定的浏览器,可以通过 targets 来配置,preset-env 会根据配置生成相符合的代码:

{
    "presets":[
        ["@babel/preset-env", {
            "targets": {
                "chrome": 88
            }
        }]
    ]
}

合理的配置,能减少很多无用的代码;

对于 preset-env ,syntax 语法很容易就转好了,但 api 不会做任务处理,比如:

const 属于 syntax 语法,但 includes 并没有被转译。如果运行在不支持 includes 的浏览器中就会报错。

core-js

babel 使用 polyfill 来处理 api,@babel/preset-env 中有个配置选项 useBuiltIns,用来告诉 babel 如何处理 api,它的默认值是 false,即默认不处理任何 api。

{
    "presets":[
        ["@babel/preset-env",{
            "useBuiltIns": "usage"
        }]
    ]
}

useBuiltIns 还有一个选项是entry, 即在项目入口处把整个 polyfill 引入,这样会导致包非常大,而我们需要的仅仅是能支持 includes 而已。所以不用 entry 而使用 usage ,它会根据使用 api 的情况来按需加载需要用到的 polyfill 。这里的 polyfill 来自 core-js这个库,所以完整配置如下:

{
    "presets":[
        ["@babel/preset-env",{
            "useBuiltIns": "usage",
            "corejs" 3
        }]
    ]
}

@babel/plugin-transform-runtime

babel 在转译 syntax 时,会经常使用一些辅助函数来帮忙转译,比如 class 语法中,babel 自定义了 _classCallCheck 这个辅助函数;typeof 则被重新自定义了一个 _typeof 辅助函数。这些函数叫做 helpers,一个项目中如果每个文件都有这些函数,显然会不合理。

@babel/plugin-transform-runtime就是为了解决这个问题:

  • api 从之前的直接修改原型改为从一个统一模块中引入,避免全局变量和原型的污染
  • heplers 从之前在当前文件中定义,改为从一个统一的模块中引入,这样打包结果中每个 hepler 只会存在一个

使用 @babel/plugin-transform-runtime

yarn add @babel/plugin-transform-runtime @babel/runtime -D

然后配置一下

"plugins":[
        ["@babel/preset-env",{
            "useBuiltIns": "usage",
            "corejs" 3
        }]
]

总结

  1. babel 在转译过程中,对 syntax 语法的处里非常好,但有很多 api 是不转译的,比如数组的 includes 方法

  2. preset-env 转译 JavaScript ,可以通过 useBuiltIns 来设置 core-js ,用于解决 api 的 polyfill

  3. babel 转译时,会自定义一些 helpers 函数,可以通过 @babel/plugin-transform-runtime 来抽离这些 heplers 统一导入

chenlong-io avatar Jan 27 '21 11:01 chenlong-io