babel
# babel
# 一、基础介绍
Babel 是⼀个 JavaScript 编译器。
Babel 是⼀个⼯具链(依赖于生态,如:插件),主要⽤于将采⽤ ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运⾏在当前和旧版本的浏览器或其他环境中。
- 语法转换
- Polyfill
- 源码转换
# 二、基本流程
Babel⼯作原理本质上就是三个步骤:parse、transform 和 generator。
const { parse } = require('@babel/parser');
const { default: generate } = require('@babel/generator');
const source = `const name = 'babel'`;
const ast = parse(source);
console.log(ast.program.body[0], ast.program.body[0].declarations);
/**
* 在这里做代码转换
*/
const code = generate(ast);
console.log(code);
2
3
4
5
6
7
8
9
10
11
12
13
14
# 三、解析器
在babel中编译器插件是 @babel/parser
,其作⽤就是将源码转换为 AST
# 四、转换器
插件发挥作⽤的地⽅基本就是在 tranfrom 这个流程了,当源码通过 parse ⽣成了 ast 后,即可通过转换插件,操作 ast。
@babel/types
用于创建、修改、删除、查找ast节点。
@babel/traverse
⽤于对 ast 进⾏遍历,在遍历的过程中可以定义回调函数,回调函数的参数提供了丰富的增、删、改、查以及类型断⾔的⽅法,⽐如 replaceWith / remove / find / isMemberExpression。
# 五、生成器
使⽤的插件是 @babel/generator
,其作⽤就是将 ast 重新⽣成指定类型的代码。
const { parse } = require('@babel/parser');
const { default: traverse } = require('@babel/traverse');
const { default: generate } = require('@babel/generator');
const source = `const name = 'babel'`; // 原始代码
const ast = parse(source);
traverse(ast, {
VariableDeclaration(path) {
const { node } = path;
if (node.kind === 'const') {
path.node.kind = "var";
}
}
});
const code = generate(ast, {}, source);
console.log(code);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 六、核心插件
babel-core
包含 babel 的核心功能的封装,如 @babel/parse
、@babel/generator
、@babel/types
、@babel/traverser
等等。
const babel = require("@babel/core");
const constPlugin = ({ types: t }) => ({
visitor: {
VariableDeclaration(path) {
const { node } = path;
if (node && node.kind === 'const') node.kind = "var";
}
}
})
const code = `const name = babel;`;
babel.transform(code, {
plugins: [constPlugin],
babelrc: false
}, (err, result) => {
if (!err) console.log(result.code)
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 七、插件的使⽤
执行时序
插件在 Presets 前运⾏
执行顺序
插件从前往后执行
插件的短名称
如果插件名称为 @babel/plugin-XXX,可以使⽤短名称@babel/XXX
如果插件名称为 babel-plugin-XXX,可以使⽤短名称 XXX
Babel 的插件分为两种: 语法插件和转换插件。
语法插件
作⽤于
@babel/parser
,在将代码解析为 AST 时解析语法
转换插件
作⽤于
@babel/core
,在对 AST 进行遍历时进行转换。
# 1、安装依赖
@babel/core
: 核⼼库
@babel/cli
: CLI命令⾏⼯具
npm install -D @babel/core @babel/cli
# 2、配置
项⽬维度的配置⽂件,也叫全局配置文件,一般文件名为 babel.config.js
或 .babelrc
。
相对路径的配置⽂件,一般文件名为 .babelrc
,babel 在决定⼀个⽂件应⽤什么配置时,会执⾏如下策略(文件必须在当前项目):
1、从当前路径递归往上查找 .babelrc
⽂件
2、查找全局配置合并。
# presets
执行顺序
Preset 从后往前执行
插件的集合
@babel/preset-env
用于对所使⽤的⽬标浏览器中缺失的功能进⾏代码转换和 polyfill。
@babel/preset-env
默认包含的插件将⽀持所有最新的 JS 特性,如 ES2015、ES2016等(不包含 stage 阶段),将其转换成ES5代码。
{
"presets": ["@babel/preset-env"]
}
2
3
@babel/preset-env
会根据⽬标环境,⽣成插件列表来编译。对基于浏览器或 webview 的项⽬,官⽅推荐使⽤ .browserslistrc ⽂件来指定⽬标环境。
默认情况下,若没有在 Babel 配置⽂件中设置 targets 或 ignoreBrowserslistConfig,@babel/preset-env
会使⽤ browserslist 配置源。
# Polyfill
@babel/polyfill 模块包括 core-js
和⼀个⾃定义的 regenerator runtime 模块,可以模拟完整的 ES2015+ 环境(不包含第4阶段前的提议)。
从 V7.4.0 版本开始,官⽅不再推荐使⽤此模块
# preset 与 polyfill
@babel/preset-env
与 @babel/polyfill
的相关参数如下:
targets: ⽀持的⽬标浏览器的列表
useBuiltIns: 参数有 "entry"、"usage"、false 三个值。默认值是 false,此参数决定了 babel 打包时 如何处理
@babel/polyfilll
语句corejs: useBuiltIns 设置值为 usage 时有效 (若不设置,会给出警告,默认使⽤的是"corejs": 2)
core-js@2 分⽀中已经不会再添加新特性,新特性都会添加到 core-js@3。
useBuiltIns的不同配置如下:
- entry: 去掉⽬标浏览器已⽀持的 polyfilll 模块,将浏览器不⽀持的都引⼊对应的 polyfill 模块
- usage: 打包时会⾃动根据实际代码的使⽤情况,结合 targets 引⼊代码⾥实际⽤到部分 polyfill 模块
- false: 不会⾃动引⼊ polyfilll 模块,对polyfilll模块屏蔽
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
]
}
2
3
4
5
6
7
8
# @babel/runtime
base.js
export class Base {
console(message) {
console.log(message)
}
}
2
3
4
5
index.js
import { Base } from './base'
class A extends Base {
console(message) {
super.console('a:', message)
}
}
let a = new A()
a.console('done')
2
3
4
5
6
7
8
9
10
两个⽂件在编译 class 语法时,都用到了辅助⽅法:_createClass
、 _classCallCheck
。
有相同代码的地方就有优化,因此这里引用了 @babel/plugin-transform-runtime
。
@babel/plugin-transform-runtime
就是⼀个可用于解决重复进行 Babel 注⼊以缩减代码体积的插件。
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
],
"plugins": [
["@babel/plugin-transform-runtime"]
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
引入后,相同的辅助⽅法不会在每个⽂件中单独定义,⽽是从 @babel/runtime/helpers
中统⼀引⼊。
@babel/plugin-transform-runtime
还能为代码创建⼀个沙盒环境。
在使⽤ @babel/polyfill 及其提供的内置程序(如:ES6 的特性 ),会在全局作用域中进行挟持,虽然解决了兼容问题,但是若代码是要发布到社区的库,又或⽆法决定代码运⾏的环境,则劫持就会成为污染。
@babel/plugin-transform-runtime
的另一个作用则是将这些内置别名作为 core-js 的别名,可以进行使⽤,但并不会污染全局作用域。
corejs选项与相关按照、说明
选项 | 安装命令 | 说明 |
---|---|---|
false | npm i @babel/runtime | 只提供公共的帮助⽅法,⾼级语法和 API 仍需依赖 @babel/polyfill 转译 |
2 | npm i @babel/runtime-corejs2 | ⽀持全局变量(例如Promise)和静态属性(例如Array.from) |
3 | npm i @babel/runtime-corejs3 | 还⽀持实例属性(例如[].includes) |
{
"presets": [
["@babel/preset-env"]
],
"plugins": [
["@babel/plugin-transform-runtime", {
"corejs": 3
}]
]
}
2
3
4
5
6
7
8
9
10