babel基础
徐徐 抱歉选手

参考前端科普系列-Babel:把 ES6 送上天的通天塔

Babel是Javascript编译器。可以针对不同类型/版本的浏览器对ECMAScript的支持程度,把原本不支持的代码转化为浏览器全部支持的代码;也就是Babel的转译基于浏览器环境

依赖包安装

使用babel需要安装以下依赖包。

1
npm install --save-dev @babel/core @babel/cli @babel/preset-env

@babel/preset-env是预置的常用的转换插件的集合,包含了大部分ES6语法转换常见,如果编译过程中遇到报错,也就是源码使用了不在@babel/preset-env的代码,需要在plugins中手动增加。

定义脚本

在npm scripts字段中加入babel脚本或者直接在命令行输入:babel src --out-dir dist。改名了会在工程根目录下的dist文件夹生成编译后的输出文件。

babel.config.js设置

在项目根目录添加babel.config.js,主要由presets和plugins两个部分组成。presets是告诉babel以何种配置编译,比如debug输出的结果要有babel的工作日志,target转译环境是什么等;plugins是真正进行语法转换,完成编译的插件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const presets = [
[
'@babel/env',
{
debug: true,
// 打印babel工作日志,方便查看转换了哪些语法
targets: {
chrome: '58'
// targets参数让babel基于环境做转译,浏览器支持的ES6语法就不转译
// 如果没有target参数,会默认转译所有的ES6语法
}
}
]
]
const plugins = []
module.exports = { presets, plugins }

syntax & built-in

编译的过程经历parser解析源文件,transform转换,generator生成新文件大致三个步骤。babel通过babel.config.js中设置的plugins插件来决定如何进行转换,每一个语法都有一个对应的插件,插件命名格式为@babel/plugin-xxx

Babel将ES6标准分为Syntax以及built-in两种类型。

Syntax就是语法,const,=>,let,class,import等。对于 syntax 类型的语法在转译的过程会在当前模块中注入类似 _classCallCheck_defineProperty 的 helper 函数来实现兼容。(通过查看dist下编译结果就可以知道)

Built-in就是可以通过改写覆盖的语法(感觉更像是方法),例如includes,promise。对于 built-in 类型的语法通过 require("core-js/modules/xxxx") polyfill 的方式来兼容。(通过查看dist下编译结果就可以知道)

使用core-js处理built-in

默认babel值转译syntax类型,built-in类型的处理有两种方法:1. @babel/polyfill覆盖ES6中的built-in。2. 使用core-js。

npm install --save core-js注意要用—save方式安装,因为core-js中(需要被使用到的部分或全体,看配置是usage还是entry)是要被注入到源代码中去的,以提供执行环境。

配置 useBuiltIns
在@babel/preset-env中通过useBuiltIns参数来控制 built-in的注入。它可以设置为 ‘entry’、’usage’ 和 false 。默认值为 false,不注入垫片polyfill。在设置built-in为entry或usage的时候,还要制定corejs版本,否则日志会输出井盖

设置为’entry’时,在整个项目入口import core-js即可。但是babel会把目标环境不支持的所有built-in都注入,无论是否用到,增加代码浪费空间。

设置为’usage’时,无需在项目入口处导入,且按需注入源码。

1
2
3
4
5
6
7
8
9
10
11
  const presets = [
[
'@babel/env',
{
debug: true,
useBuiltIns: 'usage',
corejs: 3,
targets: {}
}
]
]

@babel/plugin-transform-runtime

优化syntax

前面提到babel在编译过程中通过注入helper函数实现syntax语法转换。当项目中的每个模块都被注入重复的helper函数,代码量会增大。因此需要用@babel/plugin-transform-runtime复用helper函数,缩小代码体积;同时避免全局污染。

1
2
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime

接着在babel.config.js中配置:

1
2
3
4
5
6
7
8
9
const plugins = [
'@babel/plugin-proposal-class-properties',
// 这个plugin支持的preset-env中没有的语法转换
[
'@babel/plugin-transform-runtime'
// 开启@babel/plugin-transform-runtime优化syntax
// 编译后之前的helper函数会变成require的形式
]
]

built-in全局污染的解决

polyfill的运作方式是覆盖/修改原来require的模块,也就是对require的模块进行修改,直接修改原型,造成全局污染。

为了避免这个问题,只需要配置 @babel/plugin-transform-runtime 的参数 corejs。该参数默认为 false,可以设置为 2 或者 3,分别对应 @babel/runtime-corejs2 和 @babel/runtime-corejs3。

不再需要使用core-js,以及@babel/preset-env 的 useBuiltIns 和 corejs 的配置。

1
2
npm uninstall @babel/runtime
npm install --save @babel/runtime-corejs3

Babel.config.js配置如下,

1
2
3
4
5
6
7
8
9
const plugins = [
'@babel/plugin-proposal-class-properties',
[
'@babel/plugin-transform-runtime',
{
corejs: 3
}
]
]

但是不支持targets设置,也就是无法按需加载。

截至目前为止,对于 built-in 类型的语法的 polyfill,一共有三种方式:

  1. 使用 @babel/preset-env ,useBuiltIns 设置为 ‘entry’
  2. 使用 @babel/preset-env ,useBuiltIns 设置为 ‘usage’
  3. 使用 @babel/plugin-transform-runtime
  • 本文标题:babel基础
  • 本文作者:徐徐
  • 创建时间:2021-01-10 19:49:15
  • 本文链接:https://machacroissant.github.io/2021/01/10/babel/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论