Skip to main content

升级到 Babel 8 (API)

本文档列出了在 Babel 8.0.0 中引入的重大更改,以及在从 Babel 7.0.0 升级时如何调整你对 Babel 的使用。本文档面向直接使用 Babel API 的开发者,比如 Babel 插件作者,或者那些将 Babel 作为库使用的项目的作者。

🌐 This document lists the breaking changes introduced in Babel 8.0.0, and how to adapt your usage of Babel to them when upgrading from Babel 7.0.0. This document is intended for developers using Babel's API directly, such as Babel plugin authors, or authors of projects that use Babel as a library.

info

先看看Babel 8迁移指南,了解对用户有影响的重大更改。

AST 变更​

🌐 AST Changes

JavaScript 节点​

🌐 JavaScript nodes

high

  • 用一个 ImportExpression 节点表示动态 import() (#15682, #16114)。

    // Example input
    import("foo", options);

    // AST in Babel 7
    {
    type: "CallExpression",
    callee: { type: "Import" },
    arguments: [
    StringLiteral("foo"),
    Identifier("options")
    ]
    }

    // AST in Babel 8
    {
    type: "ImportExpression",
    source: StringLiteral("foo"),
    options: Identifier("options")
    }

    Migration: You are encouraged to test your Babel plugins with the new AST, starting from v7.23.0, specifying { parserOpts: { createImportExpressions: true } } in the Babel config. For end users utilizing Babel plugins that rely on the legacy import() AST, it is possible to set createImportExpressions to false. Note that the Babel 7 import() AST is now considered deprecated, it does not support new ES features such as Source Phrase Imports. We will remove the createImportExpressions parser option in Babel 9.

medium

  • 使用 bigint 来替代 BigIntLiteral.value,而不是使用字符串(#17378)

    // Example input
    0xff01_0000_0000_0000_0000_0000_0000_0001n

    // AST in Babel 7
    {
    type: "BigIntLiteral",
    value: "0xff010000000000000000000000000001",
    extra: {
    rawValue: "0xff010000000000000000000000000001",
    raw: "0xff01_0000_0000_0000_0000_0000_0000_0001n",
    }
    }

    // AST in Babel 8
    {
    type: "BigIntLiteral",
    value: 338958331222012082418099330867817086977n,
    extra: {
    rawValue: 338958331222012082418099330867817086977n,
    raw: "0xff01_0000_0000_0000_0000_0000_0000_0001n"
    }
    }

    迁移:这个变化与我们处理 NumericLiteral 的方式保持一致。如果你想在 Babel 7 中访问字符串表示,请调用 toString() bigint 实例方法。
    请注意,内置的 JavaScript 方法 JSON.stringify 无法序列化 bigint。如果你想将 Babel 8 的 AST 存储为 JSON,可以提供你自己的 bigint 序列化器。

TypeScript 节点​

🌐 TypeScript nodes

我们对 TypeScript 特定 AST 节点的大部分更改都是为了缩小与 @typescript-eslint 项目 AST 结构的差异。这会让编写 ESLint 规则更容易,当不依赖类型信息时,可以同时在 @typescript-eslint/parser 和 @babel/eslint-parser 上工作。

🌐 Most of the changes to our TypeScript-specific AST nodes are to reduce the differences with the AST shape of the @typescript-eslint project. This will make it easier to write ESLint rules that, when not depending on type information, can work both with @typescript-eslint/parser and @babel/eslint-parser.

medium

  • 对 TSTypeParameter.name 使用标识符,而不是普通字符串 (#12829)

    input.ts
    // T is a TSTypeParameter
    function process<T>(input: T): T {}

    // AST in Babel 7
    {
    type: "TSTypeParameter",
    name: "T",
    }

    // AST in Babel 8
    {
    type: "TSTypeParameter",
    name: { type: "Identifier", name: "T" },
    }
  • 允许将 ThisExpression 当作 TSTypeQuery.exprName,而不是 this 标识符 (#17059)

    input.ts
    function fn() {
    // `typeof this` is a TSTypeQuery
    var self: typeof this
    }

    // AST in Babel 7
    {
    type: "TSTypeQuery",
    exprName: { type: "Identifier", name: "this" }
    }

    // AST in Babel 8
    {
    type: "TSTypeQuery",
    exprName: { type: "ThisExpression" }
    }
  • 解析将 TSImportEqualsDeclaration 作为 ExportNamedDeclaration 导出 (#17073)

    注意,isExport 字段也被移除了。对于任何 TSImportEqualsDeclaration NodePath p,使用 p.parentPath.isExportNamedDeclaration() 来检测它是否跟随 export 关键字。

    input.ts
    export import foo = require("foo")

    // AST in Babel 7
    {
    type: "TSImportEqualsDeclaration",
    importKind: "value"
    isExport: true,
    id: Identifier("foo"),
    moduleReference: {
    type: "TSExternalModuleReference",
    expression: StringLiteral("foo")
    }
    }

    // AST in Babel 8
    {
    type: "ExportNamedDeclaration",
    declaration: {
    type: "TSImportEqualsDeclaration",
    importKind: "value"
    id: Identifier("foo"),
    moduleReference: {
    type: "TSExternalModuleReference",
    expression: StringLiteral("foo")
    }
    },
    specifiers: []
    }
  • 在 TSCallSignatureDeclaration、TSConstructSignatureDeclaration、TSFunctionType、TSConstructorType 和 TSMethodSignature 中把 parameters 重命名为 params,typeAnnotation 重命名为 returnType (#9231,#13709)

    TS调用签名声明
    input.ts
    interface Foo {
    (x: number): string;
    }

    // AST in Babel 7
    {
    type: "TSCallSignatureDeclaration",
    parameters: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    typeAnnotation: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }

    // AST in Babel 8
    {
    type: "TSCallSignatureDeclaration",
    params: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    retutnType: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }
    TS构造签名声明
    input.ts
    interface Foo {
    new (x: number): string;
    }

    // AST in Babel 7
    {
    type: "TSConstructSignatureDeclaration",
    parameters: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    typeAnnotation: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }

    // AST in Babel 8
    {
    type: "TSConstructSignatureDeclaration",
    params: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    retutnType: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }
    TS方法签名
    input.ts
    interface Foo {
    foo(x: number): string;
    }

    // AST in Babel 7
    {
    type: "TSMethodSignature",
    key: Identifier("foo"),
    parameters: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    typeAnnotation: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }

    // AST in Babel 8
    {
    type: "TSMethodSignature",
    key: Identifier("foo"),
    params: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    retutnType: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }
    TS函数类型
    input.ts
    type Bar = (x: number) => string;

    // AST in Babel 7
    {
    type: "TSFunctionType",
    parameters: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    typeAnnotation: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }

    // AST in Babel 8
    {
    type: "TSFunctionType",
    params: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    retutnType: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }
    TS构造函数类型
    input.ts
    type Bar = (x: number) => string;

    // AST in Babel 7
    {
    type: "TSConstructorType",
    parameters: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    typeAnnotation: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }

    // AST in Babel 8
    {
    type: "TSConstructorType",
    params: [
    { type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
    ],
    retutnType: {
    type: "TSTypeAnnotation",
    typeAnnotation: { type: "TSStringKeyword" }
    }
    }
  • 在 CallExpression、JSXOpeningElement、NewExpression、OptionalCallExpression、TSImportType、TSInstantiationExpression、TSTypeQuery 和 TSTypeReference 中把 typeParameters 改名为 typeArguments (#16679, #17008, #17012, #17020, #17042)

    调用表达式
    input.ts
    fn<string>()

    // AST in Babel 7
    {
    type: "CallExpression",
    callee: Identifier("fn"),
    arguments: [],
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "CallExpression",
    callee: Identifier("fn"),
    arguments: [],
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
    JSX开头元素
    input.ts
    <Component<string>/>

    // AST in Babel 7
    {
    type: "JSXOpeningElement",
    name: JSXIdentifier("Component"),
    attributes: [],
    selfClosing: true,
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "JSXOpeningElement",
    name: JSXIdentifier("Component"),
    attributes: [],
    selfClosing: true,
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
    新表达
    input.ts
    new Component<string>()

    // AST in Babel 7
    {
    type: "NewExpression",
    callee: Identifier("Component"),
    arguments: [],
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "NewExpression",
    callee: Identifier("Component"),
    arguments: [],
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
    可选调用表达式
    input.ts
    fn?.<string>()

    // AST in Babel 7
    {
    type: "OptionalCallExpression",
    callee: Identifier("fn"),
    arguments: [],
    optional: true,
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "OptionalCallExpression",
    callee: Identifier("fn"),
    arguments: [],
    optional: true,
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
    TS导入类型
    input.ts
    var arr: import("./Array")<string>

    // AST in Babel 7
    {
    type: "TSImportType",
    argument: StringLiteral("./Array"),
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "TSImportType",
    argument: {
    type: "TSLiteralType",
    literal: StringLiteral("./Array")
    },
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
    TS实例化表达式
    input.ts
    fn<string>

    // AST in Babel 7
    {
    type: "TSInstantiationExpression",
    expression: Identifier("fn"),
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "TSInstantiationExpression",
    expression: Identifier("fn"),
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
    类型查询
    input.ts
    var arr: typeof Array<string>;

    // AST in Babel 7
    {
    type: "TSTypeQuery",
    exprName: Identifier("Array"),
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "TSTypeQuery",
    exprName: Identifier("Array"),
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
    类型引用
    input.ts
    var arr: Array<string>;

    // AST in Babel 7
    {
    type: "TSTypeReference",
    typeName: Identifier("Array"),
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "TSTypeReference",
    typeName: Identifier("Array"),
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
  • 在 ClassDeclaration 和 ClassExpression 中将 superTypeParameters 重命名为 superTypeArguments (#16679, #16997)

    input.ts
    class X extends Y<string> {}

    // AST in Babel 7
    {
    type: "ClassDeclaration",
    id: Identifier("X"),
    superClass: Identifier("Y"),
    superTypeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }

    // AST in Babel 8
    {
    type: "ClassDeclaration",
    id: Identifier("X"),
    superClass: Identifier("Y"),
    superTypeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [{
    type: "TSStringKeyword"
    }]
    }
    }
  • 拆分 TSMappedType 的 typeParameter (#16733)。

    TSMappedType 节点中,typeParameter 属性被展平为 TSMappedType 本身的 key 和 constraint 属性。

    input.ts
    let map1: { [P in string]: number; };

    // AST in Babel 7
    {
    type: "TSMappedType",
    typeParameter: {
    type: "TypeParameter",
    name: Identifier("P"),
    constraint: TSStringKeyword()
    },
    typeAnnotation: TSNumberKeyword(),
    }

    // AST in Babel 8
    {
    type: "TSMappedType",
    key: Identifier("P"),
    constraint: TSStringKeyword()
    typeAnnotation: TSNumberKeyword(),
    }
  • 将 TSExpressionWithTypeArguments 分成 TSClassImplements 和 TSInterfaceHeritage (#16731)。

    新的节点也使用 typeArguments 而不是 typeParameters (#17017)。如果 expression 是一个 TS 限定名称(例如 a.b),它将被解析为 MemberExpression (#17139)。

    TS类实现
    input.ts
    class C implements X<T> {}

    // AST in Babel 7
    {
    type: "ClassDeclaration",
    id: Identifier("C"),
    implements: [
    {
    type: "TSExpressionWithTypeArguments",
    expression: Identifier("X"),
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [TSTypeReference(Identifier("T"))]
    }
    }
    ],
    body: ClassBody([]),
    }

    // AST in Babel 8
    {
    type: "ClassDeclaration",
    id: Identifier("C"),
    implements: [
    {
    type: "TSClassImplements",
    expression: Identifier("X"),
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [TSTypeReference(Identifier("T"))]
    }
    }
    ],
    body: ClassBody([]),
    }
    TS接口继承
    input.ts
    interface I extends X<T> {}

    // AST in Babel 7
    {
    type: "TSInterfaceDeclaration",
    id: Identifier("I"),
    extends: [
    {
    type: "TSExpressionWithTypeArguments",
    expression: Identifier("X"),
    typeParameters: {
    type: "TSTypeParameterInstantiation",
    params: [TSTypeReference(Identifier("T"))]
    }
    }
    ],
    body: TSInterfaceBody([]),
    }

    // AST in Babel 8
    {
    type: "TSInterfaceDeclaration",
    id: Identifier("I"),
    extends: [
    {
    type: "TSInterfaceHeritage",
    expression: Identifier("X"),
    typeArguments: {
    type: "TSTypeParameterInstantiation",
    params: [TSTypeReference(Identifier("T"))]
    }
    }
    ],
    body: TSInterfaceBody([]),
    }
    限定名
    input.ts
    class C implements X.Y {}

    // AST in Babel 7
    {
    type: "ClassDeclaration",
    id: Identifier("C"),
    implements: [
    {
    type: "TSExpressionWithTypeArguments",
    expression: {
    type: "TSQualifiedName",
    left: Identifier("X"),
    right: Identifier("Y")
    }
    }
    ],
    body: ClassBody([]),
    }

    // AST in Babel 8
    {
    type: "ClassDeclaration",
    id: Identifier("C"),
    implements: [
    {
    type: "TSClassImplements",
    expression: {
    type: "MemberExpression",
    object: Identifier("X"),
    property: Identifier("Y"),
    computed: false
    }
    }
    ],
    body: ClassBody([]),
    }
  • 将 TSImportType 的 argument 重命名为 source (#17610)

    TSImportType 也使用了 typeArguments 而不是 typeParameters (#17042)。例子见 这里。

    input.ts
    var arr: import("./Array")

    // AST in Babel 7
    {
    type: "TSImportType",
    argument: StringLiteral("./Array")
    }

    // AST in Babel 8
    {
    type: "TSImportType",
    source: StringLiteral("./Array")
    }
  • 将 TSEnumDeclaration 的 members 封装在一个 TSEnumBody 节点中 (#16979)

    input.ts
    // Example input
    enum ColorType {
    Red,
    Green,
    Blue,
    }

    // AST in Babel 7
    {
    type: "TSEnumDeclaration",
    id: Identifier("ColorType")
    members: [
    EnumMember("Red"),
    EnumMember("Green"),
    EnumMember("Blue")
    ]
    }

    // AST in Babel 8
    {
    type: "TSEnumDeclaration",
    id: Identifier("ColorType")
    body: {
    type: "TSEnumBody",
    members: [
    EnumMember("Red"),
    EnumMember("Green"),
    EnumMember("Blue")
    ]
    }
    }
  • 当至少有一个插值位置时创建 TSTemplateLiteralType

    注意,当没有插值位置时 AST 不会被改变,例如 `foo` 作为模板字面量类型仍然会被解析为 TSLiteralType 内的 TemplateLiteral 节点。

    input.ts
    type World = "world";
    // `hello ${World}` is a template literal type
    type Greeting = `hello ${World}`;

    // AST in Babel 7
    {
    type: "TSLiteralType",
    literal: {
    type: "TemplateLiteral",
    expressions: [{
    type: "TSTypeReference",
    typeName: Identifier("World")
    }],
    quasis: [
    TemplateElement("hello "),
    TemplateElement("")
    ]
    }
    }

    // AST in Babel 8
    {
    type: "TSTemplateLiteralType",
    types: [{
    type: "TSTypeReference",
    typeName: Identifier("World")
    }],
    quasis: [
    TemplateElement("hello "),
    TemplateElement("")
    ]
    }
  • 当同时启用 estree 和 typescript 解析器插件时,创建 TSAbstractMethodDefinition 和 TSPropertyDefinition (#16679, #17014)

    迁移: 这个重大变化是为了让库和 ESLint 插件能够同时支持 typescript-eslint 和 @babel/eslint-parser。对于大多数 Babel 插件开发者来说,你可以放心忽略这个变化,因为它不会影响 TypeScript 的转换和代码修改。不过,如果你正尝试用 @babel/eslint-parser 开发自定义的 ESLint 规则,这个变化将 Babel AST 对齐到 typescript-eslint AST。

  • 使用 TSQualifiedName 来表示 namespace X.Y {} 的名称 (#16982)

    与其将 namespace X.Y {} 表示为两个嵌套的 TSModuleDeclaration 节点,名称分别为 X 和 Y,现在它被表示为一个单独的 TSModuleDeclaration,其名称是一个 TSQualifiedName(X, Y)。这个改变使 AST 与 @typescript-eslint 解析器保持一致。

    // Example input
    namespace X.Y {}

    // AST in Babel 7
    {
    type: "TSModuleDeclaration",
    id: Identifier("X"),
    body: {
    type: "TSModuleDeclaration",
    id: Identifier("Y")
    body: TSModuleBlock([]),
    },
    }

    // AST in Babel 8
    {
    type: "TSModuleDeclaration",
    id: {
    type: "TSQualifiedName",
    left: Identifier("X"),
    right: Identifier("Y"),
    },
    body: TSModuleBlock([]),
    }

low

  • 除非启用了 createParenthesizedExpression,否则不要生成 TSParenthesizedType (#9546, #12608)

    input.ts
    type T = ({});

    // Babel 8 with createParenthesizedExpression: true, and Babel 7
    TSParenthesizedType { typeAnnotation: TSTypeLiteral { members: [] } }

    // Babel 8 with createParenthesizedExpression: false
    TSTypeLiteral { members: [] }

    迁移:如果你需要关于括号的信息,请指定 createParenthesizedExpression 解析器选项。

    babel.config.json
    { "parserOpts": { "createParenthesizedExpression": true } }

    When createParenthesizedExpression is false, you can also use node.extra.parenthesized to detect whether node is wrapped in parentheses.

API 变更​

🌐 API Changes

所有软件包​

🌐 All packages

low

  • 禁止导入内部文件 (#14013, #14179, #17938)。

    迁移: 只使用导出的 API。如果你依赖 Babel 内部实现,请提交一个问题让我们知道。

@babel/core​

medium

  • 不允许同时使用 babel.transform、babel.transformFile、babel.transformFromAst、babel.parse、babel.loadOptions、babel.loadPartialConfig 和 babel.createConfigItem (#11110, #12695, #15869)。

    迁移: 上面的 API 需要一个回调参数。如果你不打算提供回调,请使用它们的同步版本:babel.transformSync、babel.transformFileSync、babel.transformFromAstSync、babel.parseSync、babel.loadOptionsSync、babel.loadPartialConfigSync 和 babel.createConfigItemSync。

low

  • 使用 browser 条件将 package.json#browser 替换为 package.json#imports (#17756)

    迁移: 这个变化只会影响到你如果你在打包 @babel/core。如果是为浏览器打包,你需要配置它使用 browser 条件,并确保它支持 package.json#imports。

@babel/generator​

low

  • 移除 CodeGenerator 类 (#16126)

    迁移: 在 Babel 8 中,未文档化的 CodeGenerator 类已被移除,请改用默认导出的 generate 函数。

    - new CodeGenerator(ast).generate()
    + generate(ast)

@babel/types​

medium

  • 在 t.identifier 构建器中拒绝无效的标识符名称 (#10917)。

    babel-plugin.js
    // Empty string is an invalid identifier name
    t.identifier("");

    迁移: 使用有效的名称调用 t.identifier。

  • 在 t.variableDeclaration 构建器中拒绝无效的变量声明器 (#10917, #17217)

    babel-plugin.js
    // var [x] is invalid without an initializer
    t.variableDeclaration("var", [
    t.variableDeclarator(t.arrayPattern([t.identifier("x")]))
    ]);
  • 从 Expression 别名中移除 Super (#14750)。

    Super 节点表示在 super 调用 super() 和 super 属性 super.foo 中的 super。由于 super 不能作为独立的表达式,t.isExpression(t.super()) 在 Babel 8 中将返回 false。

    迁移: 搜索 t.isExpression 和 t.assertsExpression 函数以及 t.Expression 类型别名的使用情况:如果它们也需要接受 Super 节点,请相应更新它们。

    my-babel-plugin.js
    // Add `.foo` to an expression
    - if (t.isExpression(path.node)) {
    + if (t.isExpression(path.node) || t.isSuper(path.node)) {
    path.replaceWith(
    t.memberExpression(
    path.node,
    t.identifier("foo")
    ))
    }

    如果没有涉及 super() 和 super.foo,你不必更新用法:

    my-babel-plugin.js
    // define an expression as a computed key of `foo`
    if (t.isExpression(path.node)) {
    path.replaceWith(
    t.memberExpression(
    t.identifier("foo"),
    // `super` can not be a computed key, so we don't update `isExpression`
    path.node,
    /* computed */ true
    ))
    }
  • 从 LVal 别名中移除 AssignmentPattern 和 RestElement (#17387)

    LVal 节点表示在赋值表达式的左侧(LHS)有效的节点。由于 AssignmentPattern 和 RestElement 不能作为 LHS,t.isLVal(t.assignmentPattern(...)) 和 t.isLVal(t.restElement(...)) 在 Babel 8 中会返回 false。

    迁移: 搜索 t.isLVal 和 t.assertsLVal 函数以及 t.LVal 类型别名的使用情况:如果它们也需要接受 AssignmentPattern 或 RestElement 节点,你可以用 t.PatternLike 扩展 t.LVal:

    my-babel-plugin.js
    // Iterate rest element within an object pattern
    for (const propertyPath of path.get("properties")) {
    - if (t.isLVal(propertyPath.node)) {
    + if (t.isLVal(propertyPath.node) || t.isPatternLike(propertyPath.node)) {
    doSomethingWith(propertyPath);
    }
    }
  • 从 LVal 别名中移除 TSParameterProperty (#17391)

    LVal 节点表示赋值表达式左侧(LHS)的有效节点。TSParameterProperty 是一种特殊的函数参数类型,只允许在类构造函数中使用。由于 TSParameterProperty 不能作为 LHS,t.isLVal(t.tsParameterProperty(...)) 在 Babel 8 中会返回 false。

  • 要求 t.bigIntLiteral 的唯一参数为 bigint (#17378)

    这是由于相应的 AST 形状变化。

    迁移: 将 bigint 原语传递给 bigIntLiteral 构建器。在 bigIntLiteral 构建器中对 bigint 的支持从 Babel 7.28 开始,你可以在升级到 Babel 8 之前开始迁移。

    my-babel-codemod.js
    t.bigIntLiteral(
    - "0xff020000000000000000000000000002"
    + 0xff020000000000000000000000000002n
    )
  • 要求将 Identifier 节点作为 t.tsTypeParameter 的第三个参数 (#12829)

    这是由于相应的 AST 形状变化。

    迁移: 在 identifier 构建器中封装 name 字符串

    my-babel-codemod.js
    t.tsTypeParameter(
    /* constraint */ undefined,
    /* default */ undefined,
    + t.identifier(
    name
    + )
    )
  • 要求将 TSEnumBody 节点作为 t.tsEnumDeclaration 的第二个参数 (#16979)

    这是由于相应的 AST 形状变化。

    迁移: 在 tsEnumBody 构建器中封装 members 数组

    my-babel-codemod.js
    // Create `enum ColorType { Red, Green, Blue }`
    t.tsEnumDeclaration(
    t.identifier("ColorType"),
    - [
    + t.tsEnumBody([
    t.tsEnumMember(t.identifier("Red")),
    t.tsEnumMember(t.identifier("Green")),
    t.tsEnumMember(t.identifier("Blue"))
    - ],
    + ]),
    )
  • 更新 t.tsMappedType 签名 (#16733)

    这是由于相应的 AST 形状变化。

    // Babel 7
    declare function tsMappedType(
    typeParameter: TSTypeParameter,
    typeAnnotation?: TSType,
    nameType?: TSType
    ): TSMappedType

    // Babel 8
    declare function tsMappedType(
    key: Identifier,
    constraint: TSType,
    nameType?: TSType,
    typeAnnotation?: TSType
    ): TSMappedType

    Migration: See the example below.

    my-babel-codemod.ts
    // To create { [P in string as Q]: number }

    // Babel 7
    t.tsMappedType(
    t.tsTypeParameter(t.tsStringKeyword(), undefined, "P"),
    t.tsNumberKeyword(),
    t.tsTypeReference(t.identifier("Q"))
    )

    // Babel 8
    t.tsMappedType(
    t.identifier("P"),
    t.tsStringKeyword(),
    t.tsTypeReference(t.identifier("Q")),
    t.tsNumberKeyword()
    )
  • TSModuleDeclaration 的第二个参数 (body) 不能再是 TSModuleDeclaration 了 (#16982)

  • t.tsModuleDeclaration 的第二个参数(body)不能再是 TSModuleDeclaration 节点了 (#16982)

    迁移: 要么创建一个导出 TSModuleDeclaration 的 TSModuleBlock 实体,要么创建一个名为 TSQualifiedName 的单一 TSModuleDeclaration。

    my-babel-codemod.js
    // Option 1

    // Create `namespace X.Y {}`
    t.tsModuleDeclaration(
    t.identifier("X"),
    + t.exportNamedDeclaration(
    t.tsModuleDeclaration(
    t.identifier("Y"),
    t.tsModuleBlock([])
    ),
    + ),
    )

    ```diff title="my-babel-codemod.js"
    // Option 2

    // 创建 `namespace X.Y {}`
    t.tsModuleDeclaration(
    + t.tsQualifiedName(
    t.identifier("X"),

    - t.tsModuleDeclaration( t.identifier("Y"), + ), t.tsModuleBlock([])
    - ) )

low

  • Remove Import from the Expression alias (#17867)

    When the parser option createImportExpressions is explicitly set to false, @babel/parser will generate legacy Import nodes, which represent import in dynamic imports import(). As import can not be a standalone expression, t.isExpression(t.import()) will return false in Babel 8.

    Migration: Search usage of the t.isExpression and t.assertsExpression functions, and of the t.Expression type alias: if they need to also accept Import nodes, update them accordingly.

  • Remove t.jSX* and t.tS* builder aliases (#6989, #15527)

    Migration: Use t.jsx* and t.ts* instead. For example, replace t.jSXIdentifier("foo") with t.jsxIdentifier("foo").

  • Remove selfClosing argument from t.jsxElement (#14464)


    - t.jsxElement(openingElement, closingElement, children, selfClosing?: boolean) + t.jsxElement(openingElement, closingElement, children)

    Migration: The selfClosing argument was already not used in the builder. You can safely remove it.

  • Remove optional argument from t.memberExpression (#13407)


    - t.memberExpression(object, property, computed, optional?: boolean) + t.memberExpression(object, property, computed)

    Migration: The optional argument was already not used in the builder. You can safely remove it.

  • Remove the Noop node type (#12361)

    Migration: There is no generic migration path: you should replace it with the actual node that Noop is being used as a placeholder for. If you are depending on Noop and have no alternative, please open an issue and explain your use case.

  • Initialize indexers, callProperties and internalSlots in the node ObjectTypeAnnotation as an empty array in t.objectTypeAnnotation (#14465)

    In Babel 7 the builder t.objectTypeAnnotation initializes them as null, this is inconsistent with how @babel/parser will parse the Flow object type annotations. In Babel 8 the new default value [] matches the parser behaviour.

  • Reject negative and NaN/infinite numbers from t.numericLiteral (#15802)

    babel-plugin.js
    // NumericLiterals must be non-negative finite numbers.
    t.numericLiteral(-1);

    Migration: To represent a negative number, use t.unaryExpression("-", t.numericLiteral(1)). To represent NaN or Infinity, use t.identifier("NaN"). To convert a generic numeric value (which could also be negative, NaN, or an inifinity) to the proper AST node, use t.valueToNode(num).

@babel/parser​

Other than the changes listed below, @babel/parser is affected by all the AST changes.

low

  • Align Babel parser error codes between Flow and TypeScript (#13294)

    The error.code for OptionalBindingPattern is renamed as PatternIsOptional.

  • Remove updateContext field from tokens[].type returned from option tokens: true (#13768)

    babel-integration.js
    import { parse } from "@babel/parser";

    const { tokens } = parse("a = 42", { tokens: true });
    tokens[0].type;
    // Babel 7
    // { label: "name", updateContext: null, ...other properties }
    // Babel 8
    // { label: "name", ... other properties }

    Note that tokens[].type is meant to be an opaque object used as an identity for token types, as if it was a symol. Its exact shape is meant to be an internal implementation detail.

  • Tokenize private names (#priv) as a single privateName token (#13256)

    babel-integration.js
    import { parse } from "@babel/parser";

    const { tokens } = parse("class C { #priv }", { tokens: true });
    tokens.filter(t => t.start >= 10 && t.end <= 15) // get tokens for `#priv`
    // Babel 7
    // [
    // Token (#) { value: "#", start: 10, end: 11 },
    // Token (name) { value: "priv", start: 11, end: 15 }
    // ]
    // Babel 8
    // [
    // Token (privateName) { value: "priv", start: 10, end: 15 }
    // ]

  • Tokenize template literals as templateNonTail and templateTail (#13919)

    babel-integration.js
    import { parse } from "@babel/parser";

    const { tokens } = parse("`head${x}middle${y}tail`", { tokens: true });
    console.log(tokens); // print tokens
    // Babel 7
    // [
    // Token (`),
    // Token (template) { value: "head" }, Token (${),
    // Token (name) { value: "x" }, Token (}),
    // Token (template) { value: "middle" }, Token (${),
    // Token (name) { value: "y" }, Token (}),
    // Token (template) { value: "tail" }
    // Token (`)
    // ]
    // Babel 8
    // [
    // Token (templateNonTail) { value: "head" },
    // Token (name) { value: "x" },
    // Token (templateNonTail) { value: "middle" },
    // Token (name) { value: "y" },
    // Token (templateTail) { value: "tail" }
    // ]

  • Remove extra.shorthand from ObjectProperty nodes (#16521)

    Migration: Use node.shorthand rather than node.extra.shorthand.

@babel/traverse​

medium

  • Remove is, isnt, has, equals methods from NodePath (#16655)

    Migration: Directly compare properties of path.node instead.


    - functionExpressionPath.equals("id", idNode) + functionExpressionPath.node.id === idNode
    - functionExpressionPath.is("id")
    - functionExpressionPath.has("id") + functionExpressionPath.node.id
    - functionExpressionPath.has("arguments") + !!functionExpressionPath.node.arguments.length
    - functionExpressionPath.isnt("async") + !functionExpressionPath.node.async

  • Remove Scope.prototype.traverse, Scope#parentBlock and Scope#hub (#16705)

    Migration: Use scope.path methods and properties instead:


    - scope.traverse(scopeRootNode, visitor, state) + scope.path.traverse(visitor, state)
    - scope.parentBlock + scope.path.parent
    - scope.hub + scope.path.hub

  • Remove Scope.prototype.getAllBindingsOfKind and Scope.prototype.toArray (#16705)

    These methods have been removed as they are not used anymore in our code base.

    Migration: You can copy&paste them from Babel 7's source to your plugin.

  • Remove hoist, updateSiblingKeys, call, setScope, resync, popContext, pushContext, setup, setKey, visit methods from NodePath (#16655, #17722)

    These methods are meant to be private so there is no real migration approach. If your plugin / build is broken by this change, feel free to open an issue and tell us how you use these methods and we can see what we can do after Babel 8 is released.

  • Remove NodePath.prototype.toComputedKey and Scope.prototype.buildUndefinedNode (#17907, #17937)

    Migration: Use t.toComputedKey and t.buildUndefinedNode from @babel/types instead.

low

  • Remove block argument from Scope#rename (#15288)


    - rename(oldName: string, newName?: string, block?: t.Pattern | t.Scopable) + rename(oldName: string, newName?: string)

    Migration: Instead of passing a different block to scope.rename(), directly call .rename() on the scope corresponding to that block.

  • Replace Scope#uids and Scope#references with Scope#uidsSet and Scope#referencesSet (#16624)

    They have been changed from objects with boolean values to Set objects. In addition to that, they are now only defined on the program scope (scope.getProgramParent()) rather than on all scope objects.


    - 如果 (programScope.references["foo"]) + 如果 (programScope.referencesSet.has("foo"))

  • Allow skipped NodePaths to be requeued (#13291)

    NodePath#requeue() can requeue a skipped NodePath. This is actually a bugfix, but it causes an infinite loop in the temporal dead zone implementation of @babel/plugin-transform-block-scoping in Babel 7: it may break other plugins as well.

    Migration: If you want to preserve the old behavior, you can use NodePath#shouldSkip to check whether a NodePath has been skipped before calling NodePath#requeue().

  • Remove methods starting with _ from Scope and NodePath (#16504, #16705)

    // NodePath.prototype
    _assertUnremoved
    _call
    _callRemovalHooks
    _containerInsert
    _containerInsertAfter
    _containerInsertBefore
    _getKey
    _getPattern
    _getQueueContexts
    _getTypeAnnotation
    _markRemoved
    _remove
    _removeFromScope
    _replaceWith
    _resolve
    _resyncKey
    _resyncList
    _resyncParent
    _resyncRemoved
    _verifyNodeList

    // Scope.prototype
    _从映射重命名
    _生成唯一ID

    These methods are meant to be private so there is no real migration approach. If your plugin / build is broken by this change, feel free to open an issue and tell us how you use these methods and we can see what we can do after Babel 8 is released.

@babel/eslint-plugin​

low

  • Remove the default property of the exports object (#14180)

    Migration: This change has no effect if you are using the plugin in your ESLint config. However, if you are extending @babel/eslint-plugin, ensure that you obtain exports from require("@babel/eslint-plugin") rather than require("@babel/eslint-plugin").default.

    my-eslint-plugin.cjs
    // Don't add `.default` after `require()`
    const { rules, rulesConfig } = require("@babel/eslint-plugin")

@babel/code-frame​

medium

  • Use 0-based column in codeFrameColumns (#17849)

    Babel 7 interpreted column as 1-based. Babel 8 treats it as 0-based, matching @babel/parser AST locations.

    Migration: If you were adding + 1 to an AST loc.column before passing it to codeFrameColumns, drop that. If you were passing a 1-based column directly, subtract 1 before calling codeFrameColumns.

    my-babel-plugin.js

    - codeFrameColumns(code, { start: { line: loc.line, column: loc.column + 1 } }); + codeFrameColumns(code, { start: { line: loc.line, column: loc.column } });

low

  • Remove default export (#17772)

    The default export was an old API which had been long deprecated since Babel 7.

    Migration: Migrate to the codeFrameColumns API.

    my-babel-plugin.js

    - import codeFrame from "@babel/code-frame";
    - codeFrame(input, 1, 0, { /* 选项 */ });

    + 从 "@babel/code-frame" 导入 { codeFrameColumns };
    + codeFrameColumns(input, { start: { line: 1, column: 0 } }, { /* 选项 */ });

@babel/compat-data​

medium

  • Rename stage 4 plugin entries from proposal-* to transform-* in plugins.json (#14976)

    This change also affects the isRequired function of @babel/helper-compilation-targets, which receives plugin names as its first parameter.

    Migration: For example, use transform-class-properties rather than proposal-class-properties. For a complete list of renamed plugin, see Packages Renames section of Babel 8 migration.

    my-babel-plugin.js
    module.exports = api => {
    const targets = api.targets();
    // The targets have native optional chaining support
    // if `transform-optional-chaining` is _not_ required
    const optionalChainingSupported = !isRequired(

    - "proposal-optional-chaining",+ "transform-optional-chaining",targets ); };

  • Directly export data as JSON files (#17267)

    The entrypoints of the package are now JSON files, rather than JS files.

    Migration: If you are importing this package from ESM, you will need to change your imports adding with { type: "json" } to them.

low

  • Remove ios_saf from data/native-modules.json (#15068)

    Migration: Use ios instead.

@babel/preset-env​

low

  • Remove the undocumented isPluginRequired API (#17670).

    Migration: This is an undocumented API. Use isRequired from @babel/helper-compilation-targets instead.

    my-babel-plugin.js

    - import { isPluginRequired } from "@babel/preset-env"; + import { isRequired } from "@babel/helper-compilation-targets";
    - isPluginRequired({ chrome: 120 }, { chrome: 90, firefox: 90 }) + isRequired("feature-name", { chrome: 120 }, { + compatData: { + "feature-name": { chrome: 90, firefox: 90 } + } + });

  • Remove the undocumented ./data/ sub-exports (#17701).

    Migration: The ./data/ sub exports are meant for use by @babel/preset-env. Refer to the following replacement table if your project relies on any of those internal files.

    Babel 7Babel 8
    @babel/preset-env/data/builtin-modules.js@babel/compat-data/native-modules
    @babel/preset-env/data/built-inscore-js-compat/data.json
    @babel/preset-env/data/core-js-compatcore-js-compat/data.json
    @babel/preset-env/data/plugins@babel/compat-data/plugins
    @babel/preset-env/data/unreleased-labels@babel/helper-compilation-targets (.unreleasedLabels)

@babel/helper-replace-supers​

low

  • Remove named export environmentVisitor (#15550)

    Migration: Import it from @babel/helper-environment-visitor.


    - import { environmentVisitor } from "@babel/helper-replace-supers"; + import environmentVisitor from `@babel/helper-environment-visitor`;

  • Remove named export skipAllButComputedKey (#15550)

    Migration: Use requeueComputedKeyAndDecorators instead. Find and replace the following import and usage

    my-babel7-plugin.js
    import { skipAllButComputedKey } from "@babel/helper-replace-supers";
    skipAllButComputedKey(path);

    to

    my-babel8-plugin.js
    import { requeueComputedKeyAndDecorators } from `@babel/helper-environment-visitor`;
    path.skip();
    requeueComputedKeyAndDecorators(path);

@babel/helper-simple-access​

low

  • Remove the the third parameter includeUpdateExpression from the default export (#15550)

    Note that the Babel 8 behavior is the same as the default Babel 7 behavior (i.e. includeUpdateExpression: true).

@babel/highlight​

low

@babel/plugin-transform-runtime​

low

  • Replace package.json#browser with package.json#imports using a browser condition (#17756)

    Migration: This change only affects you if you are bundling @babel/plugin-transform-runtime. You will need to configure it to use the browser condition if bundling for the browser, and make sure that it supports package.json#imports.

Plugin API changes​

medium

  • Remove getModuleName from plugin pass (#12724)

    Migration: Use .file.getModuleName instead.

    my-babel-plugin.js
    module.exports = {
    name: "my-babel-plugin",
    visitor: {
    Identifier(path, pass) {

    - const moduleName = pass.getModuleName(); + const moduleName = pass.file.getModuleName(); } } }

low

  • Remove addImport from plugin pass (#15576)

    This change probably will not affect your plugin as this method is already throwing an error in Babel 7.

    Migration: Use addNamed or addDefault from @babel/helper-module-imports instead.

  • Stop supporting plugin fields as named exports (#15576)

    For example, the following file is not a valid plugin anymore:

    legacy-babel-plugin.js
    export const name = "legacy-babel-plugin";
    export const visitor = {
    Identifier() {}
    }

    Migration: Find such patterns and use a default export instead, either exporting a plugin object or a factory function.

    my-babel-plugin.cjs
    export default {
    name: "babel-plugin",
    visitor: {
    Identifier() {}
    }
    }