简述
Babel 是一个解决 javascript 兼容性问题的工具链,它支持将 ECMAScript 2015 及更新的 javascript 代码转换为可兼容早期 javascript 版本的代码,从而兼容不同浏览器或者其他运行环境(如不同的 node.js 版本)。从本质上讲,Babel 就是一个编译器。
下面示例把 ES2015 的箭头函数转换为了 funtion
函数:
// Input: ES2015 arrow function
[1, 2, 3].map((n) => n + 1);
// Output: ES5 equivalent
[1, 2, 3].map(function(n) {
return n + 1;
});
安装 & 运行
安装三个包
至少在项目中安装以下包(开发环境中安装即可):
yarn add --dev @babel/core @babel/cli @babel/preset-env
如果要支持 typescript,则需要再多安装一个预设环境:
yarn add --dev @babel/preset-typescript
配置Babel
Babel版本≥v7.8
如果你的 Babel 版本大于等于 v7.8.0
,则可以使用 json 文件来配置。在项目根目录中创建一个名为 babel.config.json
的文件,基本内容为:
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1",
"node": "current",
},
"useBuiltIns": "usage",
"corejs": "3.6.5",
}
]
]
}
简单来说,上面文件通过 presets
字段预置了 @babel/env
环境。其中,指定了目标运行环境及其版本号;babel 将会把源码转换为能够适配这些运行环境的代码。
如果和你的运行环境不同,可依具体情况修改、增加或减少目标平台及版本。
Babel版本小于v7.8
如果 Babel 版本小于 v7.8.0
,则需要通过 js 文件来配置。在项目根目录中创建一个名为 babel.config.js
的文件,内容为:
const presets = [
[
"@babel/env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
node: "current",
},
useBuiltIns: "usage",
"corejs": "3.6.4",
},
],
];
module.exports = { presets };
本文将以该方式进行说明
编译
编译单个文件
在项目的 src
目录下创建一个文件 test.ts
:
const welcome = (name: string): string => {
return `Hello ${name}`;
}
console.log(welcome.toString())
console.log(welcome("linxiaozhou"))
在项目根目录执行命令:
./node_modules/.bin/babel src/test.js --out-file dist/test.js
Babel会将 src/test.ts
文件进行编译,同时将编译后的文件输出到 dist/test.js
。
如果你不想用 typescript,则将
.ts
改为.js
即可。
或者更简单地、使用 npx
(npm package runner,[email protected] 及更高版本提供)命令:
npx babel src/test.ts --out-file dist/test.js
如果不指定
--out-file dist/test.js
输出的路径,则 Babel 会直接把编译后的文件在控制台打印出来:
编译指定目录
将 src
目录下的全部文件转换并存储在 dist
目录中:
npx babel src --out-dir dist
如果要编译 typescript 代码,必须显式地指定后缀名(--extensions ".ts"
或使用简写 -x ".ts"
),而如果代码中既有 js 又有 ts,则可以指定两种:
npx babel src -x ".js,.ts" --out-dir dist
写进package.json
为了方便我们部署,可以将编译的命令直接写进 package.json
:
{
...
"scripts": {
"build": "babel src -x \".js,.ts\" --out-dir dist",
...
}
运行
有时候我们需要在 node.js 环境下通过命令直接运行编译后的 javascript 或 typescript 文件、并且不想先 build 出一个文件。此时我们就需要一个安装一个 @babel/node
工具:
yarn add --dev @babel/node
基本命令格式为:
babel-node [options] [ -e script | script.js ] [arguments]
详情可参看下面链接: https://babeljs.io/docs/en/babel-node
编译并运行js文件
在项目根目录中创建一个测试文件 test.js
:
const welcome = name => {
return `Hello ${name}!`;
};
console.log(welcome("linxiaozhou"));
然后执行 npx babel-node --extensions \".js,.ts\" test.js
:
编译并运行ts文件(含ts语法)
在项目根目录中创建一个测试文件 test.ts
:
const welcome = (name: string): string => {
return `Hello ${name}!`;
};
console.log(welcome.toString());
console.log(welcome("linxiaozhou"));
然后执行 npx babel-node -x ".ts" --inspect --presets @babel/preset-env test.ts
:
如果出现报错,可在命令中加上
--inspect
或写入package.json
文件并通过yarn
命令运行。
使用 npx babel-node
命令 需要注意以下几点:
- 不要 在生产环境中使用它,否则会导致内存占用过高
- 先安装
@babel/node
和@babel/core
,再使用npx babel-node
命令,否则npx会安装过期的babel-node
配置你的Babel
Babel的工作原理
Babel 是一个编译器,通过 Babel 可以将源码编译成目标代码:
如果把 Babel 看做一个黑盒,则黑盒内需要通过 解析(parsing)
-> 转换(transforming)
-> 打印(printing)
(有些地方叫 代码生成Generate
)三个步骤来实现源码的编译。
而其中最为关键的步骤就是 转换(transforming )
。如果里面什么也没做,那么输出的就是源码本身。而这个步骤是插件式的,里面堆满了(也可能一个都没有)插件,在我们触发了 Babel 的编译动作后, Babel 内核会使用这些插件对源码进行转换,从而实现编译的功能。
这里有两个关键词需要理解:
- 插件 Plugins
即转换插件(Transform Plugins),每一个插件都可用于转换你的源码。如果你想看看有哪些插件可用,可以阅读官方文档。
官方文档:https://babeljs.io/docs/en/plugins#transform-plugins - **预置库 Presets **
提供了按照一定规则组织插件的方式,支持用户使用官方提供、其他用户共享或者用户自己定义预置库,每一个预置库都可以批量声明使用哪些插件、每个插件的参数是什么。Babel提供了一些常用的预置库,可以参考官方文档。
官方文档:https://babeljs.io/docs/en/presets
可以说,每一个独立的插件(Plugins)都各自规定了转换源码的规则,而预置库(Presets)则用于组织多个插件,两者都有各自的应用场景。
配置方式
关于配置方式的说明,可以参考这篇官方文档:
https://babeljs.io/docs/en/config-files#configuration-file-types
针对 Babel 的配置,有以下几种方式:
- 配置文件:通过配置文件来指定项目或文件夹(模块)的 Babel 配置
- 命令行:通过
@babel/cli
命令行来执行指定的 Babel 配置 - API: 通过
@babel/core
调用api的方式来使用指定的 Babel 配置
配置文件
以文件形式进行 Babel 配置则有两种方式:
- 项目范围配置(Project-wide configuration): 前文提到的 Babel 版本≥ v7.8.0的
babel.config.json
或 Babel 版本小于 v7.8.0的babel.config.js
都属于项目层面的Babel配置 - 目录配置(File-relative configuration): 可以通过遍历项目内各文件夹(模块)中的
.babelrc.json
文件和package.json
(含babel
字段内容),来单独指定这个文件夹(模块)的编译要求
而配置文件又可以分为两类:json 和 js,其书写规则分别为:
{
"presets": [...],
"plugins": [...]
}
和
module.exports = function (api) {
api.cache(true);
const presets = [ ... ];
const plugins = [ ... ];
return {
presets,
plugins
};
}
此外,package.json
的书写规则有一些不同,需要在 babel
字段下书写,例如:
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": [ ... ],
"plugins": [ ... ],
}
}
如果需要写一个拓展性好的配置文件,建议使用 js 文件来书写。这样可以通过指定不同的环境来增减插件及预置。下面官方例子中,通过全局环境的判断,为线上环境增加新的插件。
const presets = [ ... ];
const plugins = [ ... ];
if (process.env["ENV"] === "prod") {
plugins.push(...);
}
module.exports = { presets, plugins };
命令行
在通过命令行来执行 Babel 命令时,可以通过 --plugins
来指定使用的插件、通过 --presets
来指定预置库
babel --plugins @babel/plugin-transform-arrow-functions script.js
API
下面给出了一个官方示例:
require("@babel/core").transform("code", {
plugins: ["@babel/plugin-transform-arrow-functions"]
});
本文不对这部分做详细介绍,如需了解更多信息,可参考下面链接:
https://babeljs.io/docs/en/babel-core#transform
插件 Plugins
前文已经说明,插件是管理 Babel 转换规则的最小单元。Babel 提供了如下模块,每个模块都有一个或多个的插件可供使用:
- ES3
- ES5
- ES2015
- ES2016
- ES2017
- ES2018
- Modules
- Experimental
- Minification
- React
- Other
基本格式和使用
插件的声明格式为:
{
"plugins": ["pluginA", ["pluginB"], ["pluginC", {}]]
}
其中,插件 pluginC
传入了一个选项 {}
,具体的参数依插件而定。
下面给出了一个例子:
{
"plugins": [
[
"transform-async-to-module-method",
{
"module": "bluebird",
"method": "coroutine"
}
]
]
}
这里为 Babel 编译器设置了一个名为 transform-async-to-module-method
的插件,同时传入了参数:
{
"module": "bluebird",
"method": "coroutine"
}
引入路径
如果一个插件在 npm 上,可以直接声明其名称:
{
"plugins": ["babel-plugin-myPlugin"]
}
你也可以直接引入路径:
{
"plugins": ["./node_modules/asdf/plugin"]
}
简写
如果一个插件的名称是 babel-plugin-
打头,则可以简写剩余的文本:
{
"plugins": [
"myPlugin",
"babel-plugin-myPlugin" // 与上一行等价
]
}
或者,插件位于一个组织(scoped package)下:
{
"plugins": [
"@org/babel-plugin-name",
"@org/name" // 在@org下,等价于babel-plugin-name
]
}
运行顺序
当有多个插件要运行的时候,将会按声明的顺序运行。例如:
{
"plugins": ["plugin1", "plugin2", "plugin3"]
}
上面示例中,将会按这个顺序运行:plugin1
-> plugin2
-> plugin3
需要注意区分的是,预置库的运行顺序是 相反的。例如:
{
"presets": ["preset1", "preset2", "preset3"]
}
这个例子中,将会按照这个顺序运行:preset1
-> preset2
-> preset3
创建一个插件
如果想要创建一个自己的插件,可以阅读官方文档,这里不做说明。
官方文档:https://github.com/jamiebuilds/babel-handbook
预置Presets
官方提供了一些预置库供我们使用:
- @babel/preset-env: 最新的 javascript 预设配置
- @babel/preset-flow: 针对 Flow 的预设配置
- @babel/preset-react: 针对 React.js 的预设配置
- @babel/preset-typescript 针对 typescript 的预设配置
预置Presets其实是在管理各种插件 Plugins,通过组合不同的插件 Plugins 来管理编译代码的方式。如 @babel/preset-typescript 就是包含了 @babel/plugin-transform-typescript 插件
预置库的基本声明格式为:
{
"presets": [
"presetA",
["presetA"],
["presetA", {}],
]
}
其中,{}
为该预置库的选项(OPTIONS
)。
@babel/preset-env
安装
需要注意的是,Babel 不应该出现在生产环境中,因此需要加上 --dev
(npm 安装则加上--save-dev
):
yarn add @babel/preset-env --dev
书写格式
基本格式为:
{
presets: [
[
"@babel/preset-env",
]
]
}
其中,
为可选项,可以不填(但不推荐)!
下面给出了一个简单的示例:
{
presets: [
// 预置库1:preset-env
[
"@babel/preset-env",
{
targets: {
chrome: "58",
ie: "11",
},
},
],
// 其他预置库
// ...
],
}
上面示例中,presets
字段的值为数组,每个元素是一个数组;此外,每个元素也可以是一个字符串(如 "@babel/preset-typescript"
),例如:
{
presets: [
// 预置库1:preset-env
[
"@babel/preset-env",
{
targets: {
chrome: "58",
ie: "11",
},
},
],
// 预置库2:preset-typescript
"@babel/preset-typescript"`,
// 其他预置库
// ...
],
}
下面几节内容会针对一些常用的 options
作进一步说明。如需查看完整的介绍,可以打开以下链接阅读官方文档:
https://babeljs.io/docs/en/babel-preset-env#options
options.targets
targets
格式为 string | Array
,默认值为 {}
参数targets.
类型:string
说明:指定你的项目要支持的目标环境,可以支持的环境包括但不限于:chrome, opera, edge, firefox, safari, ie, ios, android, node, electron
举例:
{
targets: {
chrome: 58,
ie: 1,
}
}
参数targets.esmodules
类型:boolean
说明:如果目标浏览器支持 ES Modules,则置为 true
。如果声明了该字段,则 targets.browsers
字段会被忽略。
举例:
{
targets: {
esmodules: true
}
}
参数targets.node
类型:string | "current" | true
说明:如果要编译为当前版本 node.js 的版本,则置为 "current"
或 true
举例:
{
targets: {
node: "current"
}
}
参数targets.safari
类型:string | "tp"
说明:如果要编译为 Safiri 的预览版(technology preview),则置为 "tp"
举例:
{
targets: {
safari: "tp"
}
}
参数targets.browsers
类型:string | Array
说明:可以用单个字符串,也可以用字符串数组。其完整说明可参照这个链接:https://github.com/browserslist/browserslist#full-list
举例:
{
targets: {
browsers: "> 0.25%, not dead"
}
}
或者写作数组:
{
targets: {
browsers: [
"> 0.25%",
"not dead"
]
}
}
需要注意的是,如果 target.
有与之冲突的,会以 target.
设定的参数为准。此外,targets.browsers
参数会在后续版本中移除,可以直接写入 targets
中,例如:
{
"targets": "> 0.25%, not dead"
}
options.loose
宽松模式开关,类型为boolean
,默认为 false
。当 loose: true
时,将启用宽松模式。
下面给出了一个示例:
// INPUT
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return `(${this.x}, ${this.y})`;
}
}
在非宽松模式下,需要严格按照ES6规范来定义:
// OUTPUT: loose===false
"use strict";
var _createClass = (function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor); // (A)
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
})();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Point = (function () {
function Point(x, y) {
_classCallCheck(this, Point);
this.x = x;
this.y = y;
}
_createClass(Point, [{
key: "toString",
value: function toString() {
return "(" + this.x + ", " + this.y + ")";
}
}]);
return Point;
})();
在宽松模式下,编译出的代码更像是我们按照 ES5 规范手写的代码:
// OUTPUT: loose === true
"use strict";
function _classCallCheck(instance, Constructor) { ··· }
var Point = (function () {
function Point(x, y) {
_classCallCheck(this, Point);
this.x = x;
this.y = y;
}
Point.prototype.toString = function toString() { // (A)
return "(" + this.x + ", " + this.y + ")";
};
return Point;
})();
更多官方说明,请参看这篇文档
https://2ality.com/2015/12/babel6-loose-mode.html
options.modules
可选参数有 "amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false
,默认为 auto
其中
cjs
是commonjs
的别名
编写一个自己的预置库
如果我们有多个项目需要共享一个定制的预置库,我们可以自己编写一个预置库并发布到 npm。预置库暴露出去的 js 文件基本格式如下:
// index.js
module.exports = function() {
return {
// 包含其他预置库
presets: [
"preset1",
"preset2",
"preset3",
],
// 指定需要引入的插件
plugins: [
"pluginA",
"pluginB",
"pluginC",
]
};
}
举个例子,我们需要引入默认的预置库、同时引入两个插件:
// index.js
module.exports = () => ({
presets: [
require("@babel/preset-env"),
],
plugins: [
[require("@babel/plugin-proposal-class-properties"), { loose: true }],
require("@babel/plugin-proposal-object-rest-spread"),
],
});
引入规则
前面介绍了官方提供的预置库,同时给出了自己编写预置库的方式。那么,如何在项目中引用它们呢?
引入路径
不论是官方的还是自定义的预置库,如果是已经安装到 node_modules
的,都按照这个方式引入:
{
"presets": ["babel-preset-myPreset"]
}
例如:
{
"presets": [
"@babel/preset-react",
"babel-preset-myPreset",
]
}
如果一个预置库没有安装到 node_modules
中(即为项目的文件),则通过路径来引入:
{
"presets": ["./myProject/myPreset"]
}
例如:
{
"presets": [
"@babel/preset-react",
"./myProject/babel-preset-myPreset",
]
}
简写
上一节的第一个例子中,如果一个预置库的包名称为 babel-preset-
开头,可以简写后面的名称。例如一个预置库的包名为 babel-preset-myPreset
,则可以简写做 myPreset
:
{
"presets": [
"myPreset",
"babel-preset-myPreset" // 与上一行等价
]
}
运行顺序
如果有一个预置库如下:
{
"presets": [
"a",
"b",
"c"
]
}
则运行的顺序为:c
-> b
-> a
,它和插件的运行顺序 刚好相反。
插件与预置库的覆盖处理
如果使用了多个预置库,应该怎么覆盖相关配置呢?Babel 会:
- 使用
Object.assign
按顺序覆盖plugins
和presets
以外的字段 - 使用
Array.concat
分别合并plugins
和presets
字段。参考官方例子:
const config = {
plugins: [["plugin-1a", { loose: true }], "plugin-1b"],
presets: ["preset-1a"],
sourceType: "script"
}
const newConfigItem = {
plugins: [["plugin-1a", { loose: false }], "plugin-2b"],
presets: ["preset-1a", "preset-2a"],
sourceType: "module"
}
BabelConfigMerge(config, newConfigItem);
// returns
({
plugins: [
["plugin-1a", { loose: true }],
"plugin-1b",
["plugin-1a", { loose: false }],
"plugin-2b"
], // new plugins are pushed
presets: [
"preset-1a",
"preset-1a",
"preset-2a"
], // new presets are pushed
sourceType: "module" // sourceType: "script" is overwritten
})
注:示例来自官网、有修改。官网的示例中,合并后的
presets
应该写错了
https://babeljs.io/docs/en/configuration#how-babel-merges-config-items
基本命令
@babel/cli
为开发者提供了 Babel 命令行,我们可以在命令行中直接使用 Babel。本章将介绍几个常用的命令。
官方文档:https://babeljs.io/docs/en/babel-cli
安装
前面已经提到,在安装 Babel 的时候,一般都已经安装。如果没有,可单独执行:
yarn add --dev @babel/core @babel/cli
需要注意的是,如果你的项目中没有 package.json
文件,务必在安装之前创建一个,否则会影响 npx
的使用。(如果你不想用 npx
命令,则可以使用 ./node_modules/.bin/babel
替代 npx babel
)
编译单个文件
执行下面命令,将在控制台打印出编译后的结果:
npx babel src/test.ts
或
./node_modules/.bin/babel src/test.ts
如果需要把编译后的内容另存为一个文件,则可以加上 --out-file
或者 -o
参数并制定新文件名:
npx babel src/test.ts --out-file dist/test.js
Soure Map
Babel 提供了 Source Map,加上参数 --source-maps
:
npx babel src/test.ts --out-file dist/test.js --source-maps
编译文件夹
如果需要把整个文件夹的文件(及子文件夹里的文件)编译并指定输出目录,可以使用 --out-dir
参数。下面命令把 src
目录编译并输出到 dist
目录中:
npx babel src --out-dir dist
忽略一些文件
如果要编译的目录中有不需要编译的文件,可以设置参数为 --ignore
,如:
npx babel src --out-dir dist --ignore "src/**/*.spec.js","src/**/*.test.js"
上面命令中忽略了以 spec.js
和 test.js
结尾的全部文件。
指定插件
通过 --plugins
参数指定要使用的插件,多个预置库用逗号 ,
隔开:
npx babel src/test.ts --out-file dist/test.js --plugins=@babel/proposal-class-properties,@babel/transform-modules-amd
指定预置库
通过 --presets
参数指定要使用的预置库,多个预置库用逗号 ,
隔开:
npx babel src/test.ts --out-file dist/test.js --presets=@babel/preset-env,@babel/flow
最简项目配置参考
项目结构及源码地址
项目结构图:
.
├── dist
├── src
│ └── test.ts
├── README.md
├── babel.config.js
└── package.json
项目源码地址:
https://github.com/KKDestiny/babel-setup.git
初始化项目
新建一个项目:
yarn init
填写相关信息:
安装以下包:
yarn add --dev @babel/core @babel/cli @babel/preset-env
如果你的项目是 typescript,则还需要安装:
yarn add --dev @babel/preset-typescript
注意看上面的打印信息,安装这个预置库的同时也一起安装了typescript的插件
@babel/[email protected]
添加 ignore 文件:
dist/
node_modules/
yarn-error.log
yarn.lock
创建配置文件
在项目根目录新建 babel.config.js
文件:
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "current",
},
},
],
"@babel/preset-typescript",
],
plugins: [
],
};
这里我们指定了使用 @babel/preset-env
和 @babel/preset-typescript
这两个预置库,但没有额外的插件。
注意,如果没有引入 typescript 的预置库或插件,则在编译的时候会报错:
除了上述的方式引入 typescript,还可以通过插件的方式(记得先安装插件 yarn add --dev @babel/plugin-transform-typescript
):
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "current",
},
},
],
],
plugins: [
"@babel/plugin-transform-typescript"
],
};
添加编译命令
设置编译命令,在 package.json
文件中增加一个 scripts 的命令:
{
"scripts": {
"compile": "npx babel src -x \".js,.ts\" --out-dir dist"
}
}
这个命令是触发 Babel 编译 src
目录中的全部 js
或 ts
文件,然后拷贝到 dist
目录中。
测试
创建 src
目录,在里面创建一个 test.ts
文件:
const welcome = (name: string): string => {
return `Hello ${name}`;
}
console.log(welcome.toString())
console.log(welcome("linxiaozhou"))
在项目根目录运行 yarn compile
:
如果运行成功,会自动创建 dist
目录(如果没有),同时把 src
目录下的全部文件编译后依次拷贝到对应位置。
编译前删除旧文件
在实际项目中,我们可能进行多次编译。如果删除了其中一些文件,则再次编译是不会自动删除这些文件的。因此建议在执行编译命令之前,先删除已经编译出来的文件(夹),以确保生产环境的文件列表是干净的。
这里推荐一个包 rimraf
,它相当于执行了Linux命令 rm -rf
(强制删除文件夹及其子文件夹和包含的文件):
yarn add --dev rimraf
然后将 package.json
文件的 compile
命令改为:
{
"scripts": {
"compile": "npx rimraf dist && npx babel src -x \".js,.ts\" --out-dir dist"
}
}
最终的 package.json
文件内容为:
{
"name": "babel-setup",
"version": "1.0.0",
"main": "index.js",
"author": "linxiaozhou.com",
"license": "MIT",
"scripts": {
"compile": "npx rimraf dist && npx babel src -x \".js,.ts\" --out-dir dist"
},
"devDependencies": {
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-typescript": "^7.12.7",
"rimraf": "^3.0.2"
}
}
更进一步
编写插件
抽象语法树(Abstract Syntax Tree,AST 树)是什么?如何通过 AST 来编写插件?这个会在后面做进一步研究。
https://blog.csdn.net/weixin_42436686/article/details/112515290?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-2&spm=1001.2101.3001.4242
在学习 Prettier 的时候看到一个好工具,可以用来研究AST:
放上链接: https://prettier.io/playground
如何组织插件
可以简单地把插件分为几类:
- proposal:处于提案状态,与ES版本有关,如果提案在选定的版本中通过,则不需要再使用
- transform:比较稳定,一般不会有变动
- 其他:按需添加
如何更好地去组织这些插件、形成自己的一个预置库?这是后面需要进一步了解的内容。
运行规则
有下面这样的例子。尽管我们一般不会写成这样,但如果我们调用了多个预置库,那么不同预置库中就有可能会指定同一个插件、设置不同参数。
babel-presets/babel-preset-a.js
module.exports = function() {
return {
plugins: [
[
"@babel/plugin-transform-arrow-functions",
{
spec: true
}
],
]
};
}
babel-presets/babel-preset-b.js
module.exports = function() {
return {
plugins: [
[
"@babel/plugin-transform-arrow-functions",
{
spec: false
}
],
]
};
}
可以看到,babel-preset-a
和 babel-preset-b
中都定义了使用插件 @babel/plugin-transform-arrow-functions
,但传入的参数却不同:
- 插件
babel-preset-a
传入参数为spec: true
- 插件
babel-preset-b
传入参数为spec: false
如果a在前、b在后:
module.exports = {
presets: [
[
"@babel/preset-env",
],
"./babel-presets/babel-preset-a",
"./babel-presets/babel-preset-b",
],
plugins: [
],
};
如果b在前、a在后:
module.exports = {
presets: [
[
"@babel/preset-env",
],
"./babel-presets/babel-preset-b",
"./babel-presets/babel-preset-a",
],
plugins: [
],
};
以上两种情况下,分别会有什么结果?这个问题会在后续做进一步研究。
参考
- babel: https://babeljs.io/docs/en/
- babel-node: https://babeljs.io/docs/en/babel-node
- typescript 预置库
@babel/preset-typescript
: https://babeljs.io/docs/en/babel-preset-typescript - rimraf: https://github.com/isaacs/rimraf