终于搞懂 Babel 怎么配置了✌️

1,413 阅读4分钟

你好,我是本文作者南一。如果有发现错误或者可完善的地方,恳请斧正,万分感谢!!

前言

之前使用babel一直搞不明白@babel/runtime core-js @babel/preset-env @babel/polyfill这几个包到底有什么区别,这次专门花费2天时间学习并记录下来。

背景

为了在旧时代的浏览器抢先体验新语法新特性,我们就需要借助babel的两个能力:语法转换和API支持。

语法转换

@babel/preset-env

语法转换能力由各种plugin支持,上述语法提案支持段落有列举,但是每个新语法都需要引入一个插件很不方便,因此@babel/preset-env出现了,它内部预设了所有的语法转换插件,一次引入即可畅享。

image-4.png

我们来测试一下,是否真的有这么神奇,我准备了一个🌰

// API
const a = Promise.resolve(1);
const b = new WeakMap([[a, 1]]);
Object.assign({ }, { a: 1 });

// 语法
const fun = async () => await a;
function* gennerateFun (){
  yield a;
}
const obj = { a: 1, b: 2, c: 3 };
const { a: a1, b: b1, c: c1 } = obj;
for (let i of obj) {
  console.log(i);
}

配置如下:

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

.browserslistrc文件,设置目标环境为只能接受ES5语法,方便观察转译效果

safari >= 7

产出如下,我们注意到API都保留原状,语法都被转换了,符合预期。

image-12.png

此外,所有的语法转换函数、辅助函数都是直接在文件中定义,每个文件都重复定义,会增加代码体积,解决办法就是抽离为单独的文件,并且共享给每个文件。

@babel/runtime@babel/plugin-transform-runtime就是为解决此问题而生。

@babel/runtime 和 @babel/plugin-transform-runtime

@babel/runtime 包含了babel在运行时需要的各种辅助函数,并且是模块化的。 @babel/plugin-transform-runtime 将babel使用到的辅助函数,替换成从@babel/runtime中引入。

测试一下,配置如下:

{
  presets: [
    ["@babel/preset-env"]
  ],
  plugins: [
    ["@babel/plugin-transform-runtime"]
  ]
}

产出如下,所有辅助函数都从@babel/runtime引入,符合预期

image-13.png

API支持

core-js

上面提到API都保留原状,这在低版本浏览器中还是不能运行,解决办法也有,我们可以基于现有的API和语法实现这些新API(polyfill),恰巧已经有人帮我们做了这件事:core-js

原本我们需要手动引入所需的polyfill,如下图,不过babel已经帮我们封装好了,只需要在@babel/preset-env的添加配置项useBuiltIns,即可自动引入polyfill

image-14.png

useBuiltIns有三个选项:

  • "usage":按需引入core-js提供的polyfill
  • "entry":在应用入口全量引入core-js
  • false:不转换也不引入任何polyfill

我们前面未给@babel/preset-env配置useBuiltIns,其实对应默认值false,因此API都保留原状

配置项useBuiltIns,需要配合配置项corejs一起使用,不然你会看到如下提示,它告诉我们需要指定core-js的版本。噢~,原来core-js发展到现在已经有很多个版本了,最新的是3版本它在2版本基础上又更新了很多功能。

image-15.png

接下来我们验证一下,配置如下,并手动安装npm i core-js@3

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

产出如下,果然,为了支持新API,从core-js中引入了很多函数

image-16.png

我们进入core-js的具体实现,可以看到所实现的API都是挂载在全局global,对应浏览器就是挂载window上面。这会带来什么问题呢?

image-17.png

如果我们是开发一个公用库,那别人一安装我们的包,这些polyfill就会污染宿主应用的全局环境。这时好奇的同学就要问了,那应该怎么办呢?其实啊,core-js已经帮我们考虑到了,它也提供了不污染全局环境的引入方式,如下:

image-18.png

同时,babel又又又帮我们封装好插件了,我们只需要安装npm i @babel/runtime-corejs3,并给@babel/plugin-transform-runtime添加配置项"corejs": 3即可,记得把前面在@babel/preset-env上的配置删除哦,不然仍然可能会引入全局的polyfill

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

产出如下,所有polyfill都用了别名引入,这样就不会污染环境啦!!!

image-19.png

@babel/polyfill

细心的同学就要问了,主播主播,@babel/polyfill这个包怎么没讲呢?好,我们到node_modules中看看怎么个事,原来@babel/polyfill依赖core-js@2regenerator-runtime,可以理解为他俩的集合,但是现在已经不推荐使用了,变成版本弃子。现在可以使用@babel/runtimecore-js@2代替它。

image-20.png

结语

今天的分享就到这里啦,喜欢的伙伴可以三连支持一下,我是南一,我们下次再见,拜拜👋