升级至 Babel 7(API 变更指南)
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
升级至 Babel 7 时请参考本文档。
另请查看 v7 迁移指南 了解其他用户级变更。
所有 Babel 包
NodeJS 支持
已停止支持 Node.js 0.10 和 0.12 版本,因为这些版本已结束维护。
导出变更
Babel 包中已移除 add-module-exports 插件的使用。
此前使用该插件是为避免导出方式的破坏性变更。
如果在库中导入 Babel 包,使用 require 时可能需要改用 .default 而非 import。
@babel/core
出于性能考虑(多数工具未使用),默认将 ast 设为 false babel/babel#7436。
已移除公开但未文档化的 Pipeline 类,建议直接使用 @babel/core 暴露的转换方法 babel/babel#5376。
babel.util.* 辅助方法已被移除,util.EXTENSIONS 已移至 babel.DEFAULT_EXTENSIONS babel/babel#5487。
当文件匹配 ignore 模式或未匹配 only 模式时,调用 babel.transform 或其他转换函数可能返回 null babel/babel#5487。
已移除 state.file.opts 上的 opts.basename 选项,如需使用请根据 opts.filename 自行构建 babel/babel#5467。
移除 resolveModuleSource,建议使用 babel-plugin-module-resolver@3 的 'resolvePath' 选项 babel/babel#6343。
移除 babel.analyse,因其仅为 babel.transform 的别名。
移除 path.mark(),因 Babel 未使用且可在自定义插件中实现。
移除 babel.metadata,因插件生成的元数据始终包含在输出结果中。
移除 path.hub.file.addImport,可使用 @babel/helper-module-imports 模块替代。
+ import { addDefault } from "@babel/helper-module-imports";
function importModule(pkgStore, name, path) {
- return path.hub.file.addImport(resolvePath(pkgStore, name, path), 'default', name);
+ return addDefault(path, resolvePath(pkgStore, name, path), { nameHint: name });
}
配置变更
我们对配置查找机制进行了重大调整:
默认情况下,为给定文件搜索
.babelrc时将在package.json处停止。
Babel v6 会为每个文件持续向上查找目录层次直到找到配置文件。 这可能导致项目因使用包根目录外的配置文件(如主目录中的配置)而中断。
新增类似 Webpack 的
babel.config.js文件支持
为避免破坏 monorepo 工作流(包括 Babel 自身),我们引入了新的配置文件, 该文件基本消除了配置的层级特性。
该配置包含一个 root 选项,默认值为当前工作目录,用于定位配置文件。此选项采用绝对路径加载,因此能正确处理符号链接问题,而此前在 webpack 中可能需要手动硬编码路径。
查看 babel.config.js 文档获取更多信息:项目级配置
该文件结合新的 overrides 属性和 env 选项,可实现单一配置文件覆盖整个项目,无需再为不同文件夹创建多个配置文件。
我们默认排除 node_modules 目录,且仅在根目录搜索配置,除非显式设置 .babelrcRoots 选项数组(如 "babelrcRoots": [".", "node_modules/pkgA"])
断言 Babel 版本 #7450
插件可检测其加载的 Babel 版本。API 将公开 assertVersion 方法,支持传入语义化版本号。
该声明助手(declare helper)用于保持与 v6 的向后兼容性。
import { declare } from "@babel/helper-plugin-utils";
export default declare(api => {
api.assertVersion(7);
// ...
});
Babel 插件/预设
当前接收参数顺序为:首参为 babel 对象,次参为插件/预设选项,末参为 dirname
module.exports = function(api, options, dirname) {};
babel-parser(曾用名 Babylon)
移除
*插件选项 #301
此功能于 v6.14.1(2016年11月17日)首次引入,实际使用率极低。
通配选项已被移除,开发者需显式指定需启用的插件。
我们曾认为此设计便于工具免于频繁更新配置,但这同时导致无法轻易引入破坏性变更。
之前:
babelParser.parse(code, {
plugins: ["*"],
});
可通过以下方式恢复旧版行为:
babelParser.parse(code, {
plugins: [
"asyncGenerators",
"classProperties",
"decorators",
"doExpressions",
"dynamicImport",
"exportExtensions",
"flow",
"functionBind",
"functionSent",
"jsx",
"objectRestSpread",
],
});
详见 Babylon 的插件选项。
将
decorators插件重命名为decorators-legacy
此次重命名旨在与 @babel/plugin-proposal-decorators 的 legacy 选项对齐。新版 decorators 插件已实现最新装饰器提案。
两个提案版本语法不兼容,强烈建议在 Babel 实现新语义前继续使用 decorators-legacy。
移除
classConstructorCall插件 #291
@babel/traverse
移除 flow 绑定支持 babel/babel#6528
此变更源于 declare var foo 实际声明的是全局绑定而非局部绑定。
getFunctionParent不再返回Program,请改用getProgramParent#5923。
名为 getFunctionParent 的函数返回 Program 对象不符合语义逻辑,故移除该行为。
要获得等效行为,您需要进行如下更改:
- path.scope.getFunctionParent()
+ path.scope.getFunctionParent() || path.scope.getProgramParent()
路径替换/移除 API 现在返回由新路径组成的数组
例如,使用 Path#insertBefore 或 Path#replaceWith 现在始终会返回由新插入/替换路径组成的数组。
const node = t.nullLiteral();
const [replaced] = path.replaceWith(node);
replace.node === node; // => true
当向更高层级的作用域插入多个节点时,这尤其有用,因为您可以立即在节点的新 Path 上调用 Path API。
const parent = path.findParent(() => /* some selection criteria */);
const helperPaths = path.unshiftContainer("body", helpers);
// helperPaths can now be referenced, manipulated, etc.
AST 变更
新增 InterpreterDirective 节点 #7928
Babylon 已经可以解析 "shebang"(#!env node),但之前是作为注释放在 Program 节点中。现在我们为其创建了专门的节点。
在 Program 节点中新增 interpreter 字段。
extend interface Program {
interpreter: InterpreterDirective;
}
新增 InterpreterDirective 节点
interface InterpreterDirective <: Node {
type: "InterpreterDirective";
value: string;
}
JSX* 和 TS* 节点构建器(来自 @babel/types 包)重命名
命名规范已变更:jsx 和 ts 现在采用小写形式。
- t.jSXIdentifier()
+ t.jsxIdentifier()
通常我们使用 TypeAnnotation 区分 Flow 的节点类型,而 TypeScript 使用 TSTypeAnnotation,因此对于共享的类型节点,TypeScript 会添加 TS 前缀。
从 ArrowFunctionExpression 中移除 .expression 字段
移除 expression 字段是为了消除两个数据源导致的同步问题,避免插件需要手动保持一致性。现在您只需检查函数体是否为 BlockStatement:
return {
visitor: {
ArrowFunctionExpression({ node }) {
- if (node.expression) {
+ if (node.body.type !== "BlockStatement") {
// () => foo;
}
}
}
};
Tokens 移除
在早期版本中,tokens 总是附加在 AST 顶层。最新版 @babel/parser 移除了此行为并默认禁用,以提升解析器性能。Babel 内部所有相关用法已被移除,@babel/generator 也不再使用 tokens 进行格式化输出。
如果您的 Babel 插件当前使用了 tokens,请评估其必要性并尝试移除。若插件确实依赖 tokens,可重新启用此功能,但请注意这会影响性能,请仅在别无选择时考虑:
要启用此功能,需将 babylon 的 tokens 选项设为 true。您可以直接在插件中进行设置。
export default function() {
return {
manipulateOptions(opts, parserOpts) {
parserOpts.tokens = true;
},
...
};
}
重命名
以下节点已被重命名:
| Name 6.x | Name 7.x | Example | PR |
|---|---|---|---|
| ExistentialTypeParam | ExistsTypeAnnotation | type A = B<*>; | #322 |
| NumericLiteralTypeAnnotation | NumberLiteralTypeAnnotation | type T = 0; | #332 |
除了 AST 节点外,@babel/types 中所有对应的函数也已被重命名。
import * as t from "@babel/types";
return {
- ExistentialTypeParam(path) {
- const parent = path.findParent((path) => path.isExistentialTypeParam());
- t.isExistentialTypeParam(parent);
+ ExistsTypeAnnotation(path) {
+ const parent = path.findParent((path) => path.isExistsTypeAnnotation());
+ t.isExistsTypeAnnotation(parent);
- return t.existentialTypeParam();
+ return t.existsTypeAnnotation();
},
- NumericLiteralTypeAnnotation(path) {
- const parent = path.findParent((path) => path.isNumericLiteralTypeAnnotation());
- t.isNumericLiteralTypeAnnotation(parent);
+ NumberLiteralTypeAnnotation(path) {
+ const parent = path.findParent((path) => path.isNumberLiteralTypeAnnotation());
+ t.isNumberLiteralTypeAnnotation(parent);
- return t.numericLiteralTypeAnnotation();
+ return t.numberLiteralTypeAnnotation();
}
};
替换
以下 AST 节点的 variance 字段值已从字符串变更为名为 Variance 的专用 AST 节点 #333
该字段仅在 babylon 中启用 flow 插件时可用。
-
ObjectProperty
-
ObjectMethod
-
AssignmentProperty
-
ClassMethod
-
ClassProperty
-
Property
新的 Variance 节点类型如下所示:
type VarianceNode = {
type: "Variance",
kind: "plus" | "minus",
};
return {
Property({ node }) {
- if (node.variance === "plus") {
+ if (node.variance.kind === "plus") {
...
- } else if (node.variance === "minus") {
+ } else if (node.variance.kind === "minus") {
...
}
}
};
位置信息变更
已将 ObjectTypeIndexer 的位置信息更改为不包含分号。此举是为了与 flow-parser 保持一致并拥有相同的位置信息。#228
示例:
var a: { [a: number]: string };
{
"type": "ObjectTypeIndexer",
"start": 9,
- "end": 29,
+ "end": 28,
"loc": {
"start": {
"line": 1,
"column": 9,
},
"end": {
"line": 1,
- "column": 29
+ "column": 28
}
}
}
移除
ForAwaitStatement
AST 节点 ForAwaitStatement 已被移除,其功能由 ForOfStatement 节点中的 await 字段替代 #349
interface ForOfStatement <: ForInStatement {
type: "ForOfStatement";
+ await: boolean;
}
return {
- ForAwaitStatement(path) {
- ...
+ ForOfStatement(path) {
+ if (path.node.await) {
+ ...
+ }
}
};
RestProperty 与 SpreadProperty
两个 AST 节点 RestProperty 和 SpreadProperty 已被移除,改用 RestElement 和 SpreadElement 替代 #384
return {
SpreadElement(path) {
- ...
- },
- SpreadProperty(path) {
- ...
+ if (path.parentPath.isObjectExpression()) {
+ ...
+ } else if (path.parentPath.isArrayExpression()) {
+ ...
+ }
},
RestElement(path) {
- ...
- },
- RestProperty(path) {
- ...
+ if (path.parentPath.isObjectPattern()) {
+ ...
+ } else if (path.parentPath.isArrayPattern()) {
+ ...
+ }
}
};
更多信息请查阅 Babel 升级 PR 和 Babylon AST 规范。