跳至主内容

升级至 Babel 7(API 变更指南)

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

升级至 Babel 7 时请参考本文档。

另请查看 v7 迁移指南 了解其他用户级变更。

所有 Babel 包

NodeJS 支持

high

已停止支持 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 的向后兼容性。

JavaScript
import { declare } from "@babel/helper-plugin-utils";

export default declare(api => {
api.assertVersion(7);
// ...
});

Babel 插件/预设

当前接收参数顺序为:首参为 babel 对象,次参为插件/预设选项,末参为 dirname

JavaScript
module.exports = function(api, options, dirname) {};

babel-parser(曾用名 Babylon)

移除 * 插件选项 #301 low

此功能于 v6.14.1(2016年11月17日)首次引入,实际使用率极低。

通配选项已被移除,开发者需显式指定需启用的插件。

我们曾认为此设计便于工具免于频繁更新配置,但这同时导致无法轻易引入破坏性变更。

之前:

JavaScript
babelParser.parse(code, {
plugins: ["*"],
});

可通过以下方式恢复旧版行为:

JavaScript
babelParser.parse(code, {
plugins: [
"asyncGenerators",
"classProperties",
"decorators",
"doExpressions",
"dynamicImport",
"exportExtensions",
"flow",
"functionBind",
"functionSent",
"jsx",
"objectRestSpread",
],
});

详见 Babylon 的插件选项

decorators 插件重命名为 decorators-legacy medium

此次重命名旨在与 @babel/plugin-proposal-decoratorslegacy 选项对齐。新版 decorators 插件已实现最新装饰器提案。

两个提案版本语法不兼容,强烈建议在 Babel 实现新语义前继续使用 decorators-legacy

移除 classConstructorCall 插件 #291 low

@babel/traverse

移除 flow 绑定支持 babel/babel#6528

此变更源于 declare var foo 实际声明的是全局绑定而非局部绑定。

getFunctionParent 不再返回 Program,请改用 getProgramParent #5923low

名为 getFunctionParent 的函数返回 Program 对象不符合语义逻辑,故移除该行为。

要获得等效行为,您需要进行如下更改:

- path.scope.getFunctionParent()
+ path.scope.getFunctionParent() || path.scope.getProgramParent()

路径替换/移除 API 现在返回由新路径组成的数组 low

例如,使用 Path#insertBeforePath#replaceWith 现在始终会返回由新插入/替换路径组成的数组。

JavaScript
const node = t.nullLiteral();
const [replaced] = path.replaceWith(node);
replace.node === node; // => true

当向更高层级的作用域插入多个节点时,这尤其有用,因为您可以立即在节点的新 Path 上调用 Path API。

JavaScript
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 字段。

JavaScript
extend interface Program {
interpreter: InterpreterDirective;
}

新增 InterpreterDirective 节点

JavaScript
interface InterpreterDirective <: Node {
type: "InterpreterDirective";
value: string;
}

JSX* 和 TS* 节点构建器(来自 @babel/types 包)重命名

命名规范已变更:jsxts 现在采用小写形式。

- 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。您可以直接在插件中进行设置。

JavaScript
export default function() {
return {
manipulateOptions(opts, parserOpts) {
parserOpts.tokens = true;
},
...
};
}

重命名

以下节点已被重命名:

Name 6.xName 7.xExamplePR
ExistentialTypeParamExistsTypeAnnotationtype A = B<*>;#322
NumericLiteralTypeAnnotationNumberLiteralTypeAnnotationtype 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 节点类型如下所示:

JavaScript
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

示例:

JavaScript
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 节点 RestPropertySpreadProperty 已被移除,改用 RestElementSpreadElement 替代 #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 升级 PRBabylon AST 规范