升级到 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.
先看看Babel 8迁移指南,了解对用户有影响的重大更改。
AST 变更
🌐 AST Changes
JavaScript 节点
🌐 JavaScript nodes
-
用一个
ImportExpression节点表示动态import()(#15682, #16114)。// Example inputimport("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 legacyimport()AST, it is possible to setcreateImportExpressionstofalse. Note that the Babel 7import()AST is now considered deprecated, it does not support new ES features such as Source Phrase Imports. We will remove thecreateImportExpressionsparser option in Babel 9.
-
使用
bigint来替代BigIntLiteral.value,而不是使用字符串(#17378)// Example input0xff01_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.
-
对
TSTypeParameter.name使用标识符,而不是普通字符串 (#12829)input.ts// T is a TSTypeParameterfunction 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.tsfunction fn() {// `typeof this` is a TSTypeQueryvar 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字段也被移除了。对于任何TSImportEqualsDeclarationNodePathp,使用p.parentPath.isExportNamedDeclaration()来检测它是否跟随export关键字。input.tsexport 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.tsinterface 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.tsinterface 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.tsinterface 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.tstype 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.tstype 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.tsfn<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.tsnew 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.tsfn?.<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.tsvar 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.tsfn<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.tsvar 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.tsvar 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.tsclass 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.tslet 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.tsclass 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.tsinterface 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.tsclass 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.tsvar 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 inputenum 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.tstype World = "world";// `hello ${World}` is a template literal typetype 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-eslintAST。 -
使用
TSQualifiedName来表示namespace X.Y {}的名称 (#16982)与其将
namespace X.Y {}表示为两个嵌套的TSModuleDeclaration节点,名称分别为X和Y,现在它被表示为一个单独的TSModuleDeclaration,其名称是一个TSQualifiedName(X, Y)。这个改变使 AST 与@typescript-eslint解析器保持一致。// Example inputnamespace 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([]),}
-
除非启用了
createParenthesizedExpression,否则不要生成TSParenthesizedType(#9546, #12608)input.tstype T = ({});// Babel 8 with createParenthesizedExpression: true, and Babel 7TSParenthesizedType { typeAnnotation: TSTypeLiteral { members: [] } }// Babel 8 with createParenthesizedExpression: falseTSTypeLiteral { members: [] }迁移:如果你需要关于括号的信息,请指定
createParenthesizedExpression解析器选项。babel.config.json{ "parserOpts": { "createParenthesizedExpression": true } }When
createParenthesizedExpressionisfalse, you can also usenode.extra.parenthesizedto detect whethernodeis wrapped in parentheses.
API 变更
🌐 API Changes
所有软件包
🌐 All packages
@babel/core
-
不允许同时使用
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。
-
使用
browser条件将package.json#browser替换为package.json#imports(#17756)迁移: 这个变化只会影响到你如果你在打包
@babel/core。如果是为浏览器打包,你需要配置它使用browser条件,并确保它支持package.json#imports。
@babel/generator
-
移除
CodeGenerator类 (#16126)迁移: 在 Babel 8 中,未文档化的
CodeGenerator类已被移除,请改用默认导出的generate函数。- new CodeGenerator(ast).generate()+ generate(ast)
@babel/types
-
在
t.identifier构建器中拒绝无效的标识符名称 (#10917)。babel-plugin.js// Empty string is an invalid identifier namet.identifier("");迁移: 使用有效的名称调用
t.identifier。 -
在
t.variableDeclaration构建器中拒绝无效的变量声明器 (#10917, #17217)babel-plugin.js// var [x] is invalid without an initializert.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 patternfor (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.jst.bigIntLiteral(- "0xff020000000000000000000000000002"+ 0xff020000000000000000000000000002n) -
要求将
Identifier节点作为t.tsTypeParameter的第三个参数 (#12829)这是由于相应的 AST 形状变化。
迁移: 在
identifier构建器中封装name字符串my-babel-codemod.jst.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 7declare function tsMappedType(typeParameter: TSTypeParameter,typeAnnotation?: TSType,nameType?: TSType): TSMappedType// Babel 8declare function tsMappedType(key: Identifier,constraint: TSType,nameType?: TSType,typeAnnotation?: TSType): TSMappedTypeMigration: See the example below.
my-babel-codemod.ts// To create { [P in string as Q]: number }// Babel 7t.tsMappedType(t.tsTypeParameter(t.tsStringKeyword(), undefined, "P"),t.tsNumberKeyword(),t.tsTypeReference(t.identifier("Q")))// Babel 8t.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([])- ) )
-
Remove
Importfrom theExpressionalias (#17867)When the parser option
createImportExpressionsis explicitly set tofalse,@babel/parserwill generate legacyImportnodes, which representimportin dynamic importsimport(). Asimportcan not be a standalone expression,t.isExpression(t.import())will returnfalsein Babel 8.Migration: Search usage of the
t.isExpressionandt.assertsExpressionfunctions, and of thet.Expressiontype alias: if they need to also acceptImportnodes, update them accordingly. -
Remove
t.jSX*andt.tS*builder aliases (#6989, #15527)Migration: Use
t.jsx*andt.ts*instead. For example, replacet.jSXIdentifier("foo")witht.jsxIdentifier("foo"). -
Remove
selfClosingargument fromt.jsxElement(#14464)- t.jsxElement(openingElement, closingElement, children, selfClosing?: boolean) + t.jsxElement(openingElement, closingElement, children)Migration: The
selfClosingargument was already not used in the builder. You can safely remove it. -
Remove
optionalargument fromt.memberExpression(#13407)- t.memberExpression(object, property, computed, optional?: boolean) + t.memberExpression(object, property, computed)Migration: The
optionalargument was already not used in the builder. You can safely remove it. -
Remove the
Noopnode type (#12361)Migration: There is no generic migration path: you should replace it with the actual node that
Noopis being used as a placeholder for. If you are depending onNoopand have no alternative, please open an issue and explain your use case. -
Initialize
indexers,callPropertiesandinternalSlotsin the nodeObjectTypeAnnotationas an empty array int.objectTypeAnnotation(#14465)In Babel 7 the builder
t.objectTypeAnnotationinitializes them asnull, this is inconsistent with how@babel/parserwill 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, uset.identifier("NaN"). To convert a generic numeric value (which could also be negative, NaN, or an inifinity) to the proper AST node, uset.valueToNode(num).
@babel/parser
Other than the changes listed below, @babel/parser is affected by all the AST changes.
-
Align Babel parser error codes between Flow and TypeScript (#13294)
The
error.codeforOptionalBindingPatternis renamed asPatternIsOptional. -
Remove
updateContextfield fromtokens[].typereturned from optiontokens: true(#13768)babel-integration.jsimport { 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[].typeis 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 singleprivateNametoken (#13256)babel-integration.jsimport { 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
templateNonTailandtemplateTail(#13919)babel-integration.jsimport { 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.shorthandfromObjectPropertynodes (#16521)Migration: Use
node.shorthandrather thannode.extra.shorthand.
@babel/traverse
-
Remove
is,isnt,has,equalsmethods fromNodePath(#16655)Migration: Directly compare properties of
path.nodeinstead.- 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#parentBlockandScope#hub(#16705)Migration: Use
scope.pathmethods 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.getAllBindingsOfKindandScope.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,visitmethods fromNodePath(#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.toComputedKeyandScope.prototype.buildUndefinedNode(#17907, #17937)Migration: Use
t.toComputedKeyandt.buildUndefinedNodefrom@babel/typesinstead.
-
Remove
blockargument fromScope#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#uidsandScope#referenceswithScope#uidsSetandScope#referencesSet(#16624)They have been changed from objects with boolean values to
Setobjects. 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-scopingin Babel 7: it may break other plugins as well.Migration: If you want to preserve the old behavior, you can use
NodePath#shouldSkipto check whether a NodePath has been skipped before callingNodePath#requeue(). -
Remove methods starting with
_fromScopeandNodePath(#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_从映射重命名_生成唯一IDThese 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
-
Remove the
defaultproperty 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 fromrequire("@babel/eslint-plugin")rather thanrequire("@babel/eslint-plugin").default.my-eslint-plugin.cjs// Don't add `.default` after `require()`const { rules, rulesConfig } = require("@babel/eslint-plugin")
@babel/code-frame
-
Use 0-based
columnincodeFrameColumns(#17849)Babel 7 interpreted
columnas 1-based. Babel 8 treats it as 0-based, matching@babel/parserAST locations.Migration: If you were adding
+ 1to an ASTloc.columnbefore passing it tocodeFrameColumns, drop that. If you were passing a 1-based column directly, subtract 1 before callingcodeFrameColumns.my-babel-plugin.js- codeFrameColumns(code, { start: { line: loc.line, column: loc.column + 1 } }); + codeFrameColumns(code, { start: { line: loc.line, column: loc.column } });
-
Remove default export (#17772)
The default export was an old API which had been long deprecated since Babel 7.
Migration: Migrate to the
codeFrameColumnsAPI.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
-
Rename stage 4 plugin entries from
proposal-*totransform-*inplugins.json(#14976)This change also affects the
isRequiredfunction of@babel/helper-compilation-targets, which receives plugin names as its first parameter.Migration: For example, use
transform-class-propertiesrather thanproposal-class-properties. For a complete list of renamed plugin, see Packages Renames section of Babel 8 migration.my-babel-plugin.jsmodule.exports = api => {const targets = api.targets();// The targets have native optional chaining support// if `transform-optional-chaining` is _not_ requiredconst 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.
-
Remove
ios_saffromdata/native-modules.json(#15068)Migration: Use
iosinstead.
@babel/preset-env
-
Remove the undocumented
isPluginRequiredAPI (#17670).Migration: This is an undocumented API. Use
isRequiredfrom@babel/helper-compilation-targetsinstead.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 7 Babel 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
-
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
requeueComputedKeyAndDecoratorsinstead. Find and replace the following import and usagemy-babel7-plugin.jsimport { skipAllButComputedKey } from "@babel/helper-replace-supers";skipAllButComputedKey(path);to
my-babel8-plugin.jsimport { requeueComputedKeyAndDecorators } from `@babel/helper-environment-visitor`;path.skip();requeueComputedKeyAndDecorators(path);
@babel/helper-simple-access
-
Remove the the third parameter
includeUpdateExpressionfrom 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
-
Remove the
getChalkfunction (https://github.com/babel/babel/pull/15812)If you need to use
chalk, add it to your dependencies.
@babel/plugin-transform-runtime
-
Replace
package.json#browserwithpackage.json#importsusing abrowsercondition (#17756)Migration: This change only affects you if you are bundling
@babel/plugin-transform-runtime. You will need to configure it to use thebrowsercondition if bundling for the browser, and make sure that it supportspackage.json#imports.
Plugin API changes
-
Remove
getModuleNamefrom plugin pass (#12724)Migration: Use
.file.getModuleNameinstead.my-babel-plugin.jsmodule.exports = {name: "my-babel-plugin",visitor: {Identifier(path, pass) {- const moduleName = pass.getModuleName(); + const moduleName = pass.file.getModuleName(); } } }
-
Remove
addImportfrom plugin pass (#15576)This change probably will not affect your plugin as this method is already throwing an error in Babel 7.
Migration: Use
addNamedoraddDefaultfrom@babel/helper-module-importsinstead. -
Stop supporting plugin fields as named exports (#15576)
For example, the following file is not a valid plugin anymore:
legacy-babel-plugin.jsexport 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.cjsexport default {name: "babel-plugin",visitor: {Identifier() {}}}