一、Babel 是什么
Bebal
可以帮助我们将新 JS 语法编译为可执行且兼容旧浏览器版本的一款编译工具。
举个例子,ES6(编译前):
const fn = () => {};
ES5(编译后):
var fn = function() {}
二、Babel 的应用场景
想体验新 JS 语法带来的便捷和可读性,又希望能够向下兼容?Babel
可以帮你做到。
不仅如此,Babel
还支持解析 TS
、JSX
等多种语法,给 ES6/7/8/9 Typescript、React / Vue3 JSX 等"语法糖"带来无限的可能。
三、Babel 的基本使用
3.1 准备工作
- 新建项目:
babel-demo
- 初始化
npm
- 安装 Babel 相关依赖包
命令流程如下:
mkdir babel-demo && cd babel-demo && touch app.js
yarn init -y
yarn add @babel/core @babel/cli @babel/preset-env --dev
依赖包解释:
- @babel/core 是
Babel
的编译核心工具。 - @babel/cli 是
Babel
提供的脚手架,后面会用到并解释。 - @babel/preset-env 集成了各种 plugin 插件,后面会用到并解释。
项目结构如下:
3.2 编译 JS
- 打开
app.js
,添加如下代码:
const app = () => {
const greeting = 'World' ?? 'Tony'
console.log(`Hello,${greeting}`)
}
- 在
babel-demo
终端执行@babel/cli
提供的编译命令:
node_modules/.bin/babel app.js --out-dir lib
解释:–out-dir 表示编译的产物将会放到 lib
目录下。
如图:
.
代码与原来没有任何变化,这是因为我们还未配置任何 Babel
插件,所以 Babel
将原封不动输出。
- 指定
Babel
插件:
node_modules/.bin/babel app.js --out-dir lib --plugins=@babel/plugin-transform-arrow-functions
解释: --plugins
参数指定了 @babel/plugin-transform-arrow-functions
插件,该插件表示将 ES6 箭头函数转为 ES5。
结果:
你可能注意到 ??
这个语法没有被转换,这是 ES2020 的语法,得借助另外一个插件来完成编译,这里就不演示了,留给大家一个小作业。
你可能好奇,@babel/plugin-transform-arrow-functions
插件不安装便能引用?这块后面会作解释。
3.3 编译 Vue 中的 JSX 语法
背景:Vue3 新增了 JSX 语法, 问题来了,Vue 怎样识别 JSX 语法?这还得得益于 Babel
提供的 @babel/plugin-syntax-jsx
插件,它可以分析 JSX 语法并导出 AST 树,但不负责 标签
转换工作,于是 Vue 在 @babel/plugin-syntax-jsx
的基础上新增了支持标签转换的 @vue/babel-preset-jsx
插件。
使用:
- 安装依赖:
yarn add @vue/babel-preset-jsx
- 调整
app.js
代码,改为 Vue JSX 写法:
const app = () => {
const greeting = 'World' ?? 'Tony'
return <div>
{`Hello,${greeting}`}
</div>
}
- 执行编译:
node_modules/.bin/babel app.js --out-dir lib --presets=@vue/babel-preset-jsx
解释:@vue/babel-preset-jsx 属于 presets
,得用 --presets
参数引入,可以临时理解为它也是 plugin,只是引用方式变了而已。
结果:
可以看到,成功将 <div>
标签转成 Vue 提供的 h
函数并传参(h = render )。
3.4 编译 React 中的 JSX 语法
背景:React 最大的特点就是提供了 JSX
写法,同时也是饱受争议的一个特点,这里不过多阐述。 React 也是基于 @babel/plugin-syntax-jsx
新增了 @babel/plugin-transform-react-jsx
插件,和 Vue 一样用来兼容标签的转换。
使用:
- 安装依赖:
yarn add @babel/plugin-transform-react-jsx --dev
- 调整
app.js
语法,改为 React JSX 语法:
const app = () => {
const greeting = 'World' ?? 'Tony'
return <div>
{`Hello,${greeting}`}
</div>
}
提示:写法跟 Vue JSX 没啥区别,只有编译结果有区别。
- 执行编译:
node_modules/.bin/babel app.js --out-dir lib --plugins=@babel/plugin-transform-react-jsx
结果:
还是那股熟悉的的配方,熟悉的味道~
四、Bebel 配置
每次编译都要用 --plugins
或 --presets
指定插件太麻烦了,就像 Eslint/Typescript 那样,Babel
同样支持以配置文件的方式,只需在根目录下新建 babel.config.json
即可。
注意:如果你使用的
Babel
版本低于 v7.8.0,请用babel.config.js
格式。
4.1 将上面的插件引入配置中
@babel/plugin-transform-arrow-functions
// babel.config.json
{
"plugins": [
["@babel/plugin-transform-arrow-functions"]
]
}
@vue/babel-preset-jsx
// babel.config.json
{
"presets": [
["@vue/babel-preset-jsx"]
],
"plugins": [
["@babel/plugin-transform-arrow-functions"]
]
}
- 执行编译:
node_modules/.bin/babel app.js --out-dir lib
Babel
会自动寻找babel.config.json
文件,并引入里面的 presets
和 plugins
。
4.2 Presets vs Plugins
4.2.1 Presets
Presets
其实就是 内置了许多 plugins
,仅此而已,比如一开始安装的 @babel/preset-env
,里面就集成了许多插件,其中包括我们上面提到的 @babel/plugin-transform-arrow-functions
。
这也是为什么我们一开始要先安装 @babel/preset-env
的原因,后续可直接通过 --plugins
引用 @babel/plugin-transform-arrow-functions
。
类似的,React 和 Vue 也封装了自己的一套 presets
,比如 @vue/babel-preset-app
,里面内置了许多插件,其中就包括上面的 @babel/plugin-transform-arrow-functions
/ @babel/plugin-transform-arrow-functions
/ @babel/preset-env
等等。我们没有直接用它的原因是为了让案例更易于理解,避免被 presets
名词给混淆了。
明白了 presets
的作用后,我们便可直接安装 @vue/babel-preset-app
,并配置在 babel.config.json
中,像往常一样执行编译命令便可。
4.2.2 Plugins
说完 presets,再来聊聊 plugins
,它实际上就是一个存放单个的 plugin 的集合,
也就是说,如果你想单独用某个插件而不用整套 preset,就可以通过 plugins
来单独地引入这个插件。
五、扩展知识
5.1 babel-loader 是什么?
如果想在 webapck
使用 babel
,就得借助 babel-loader
来完成与 webpack
配合完成。
一个负责打包,一个负责编译。
5.2 Vue-cli 也能配置 babel ?
vue-cli 脚手架是基于 webpack
改造的,并提供了 vue-config.js
配置文件,里面就有一个transpileDependencies
属性可以改变 babel
的编译范围,让 babel
是否编译 node_modules/
的代码。一般情况下,vue-config.js
能够配置 babel
的属性非常少,基本都是新建一个 babel.config.json
来维护,vue-cli 在执行时会读取这份配置并合并。
六、Bebel 部分插件说明
-
@babel/core
Babel 的编译核心逻辑。 -
@babel/cli
Babel 的执行脚手架。 -
@babel/plugin-syntax-jsx
识别 JSX 并提供 AST 分析语法树,但不会做转换工作。 -
@babel/preset-env
集成了大量的 plugins ,其中包括但不限于:- @babel/plugin-transform-optional-chaining 链式语法。
- @babel/plugin-transform-arrow-functions ES6 箭头语法转换 ES5 。
- @babel/plugin-transform-block-scoping let/const 语法转换 var 。
- @babel/plugin-transform-classes class 语法转换。
- @babel/plugin-transform-destructuring 解构对象转换。
- 等等
-
@babel/preset-react
集成了有关 React 的 plugins,以下包括:- @babel/plugin-transform-react-jsx 支持 JSX & 标签转换。
- 内嵌了
Babel
自带的如:@babel/preset-env / @babel/plugin-syntax-jsx 等。
-
@vue/babel-preset-app
集成了有关 Vue 的 plugins,以下包括:- @vue/babel-preset-jsx 支持 JSX & 标签转换。
- 内嵌了
Babel
自带的如:@babel/preset-env / @babel/plugin-syntax-jsx 等。
-
@babel/preset-typescript
集成了关于 TS 的 plugins,以下包括:- @babel/plugin-transform-typescript 识别 TS 语法。
更多插件可参考:https://babeljs.io/docs/presets
完!