Upgrade to Babel 8 (Integration)
Refer plugin developers or integration users to this document when upgrading to Babel 8.
Check out the v8-migration guide for other user-level changes.
AST Changes
-
Dynamic
import()
is parsed as anImportExpression
(#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 legacyimport()
AST, it is possible to setcreateImportExpressions
tofalse
. 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 thecreateImportExpressions
parser option in Babel 9. -
Use an identifier for
TSTypeParameter.name
(#12829).For a TS type parameter
node
,node.name
is a string in Babel 7 while in Babel 8 it is an Identifier.input.ts// T is a TSTypeParameter
function process<T>(input: T): T {}Migration: If you have a customized plugin accessing the name of a type parameter node, use
node.name.name
in Babel 8. -
Rename
parameters
toparams
,typeAnnotation
toreturnType
forTSCallSignatureDeclaration
,TSConstructSignatureDeclaration
,TSFunctionType
,TSConstructorType
andTSMethodSignature
(#9231, #13709)input.tsinterface Foo {
// TSCallSignatureDeclaration
<T>(): string;
// TSMethodSignature
foo<T>(): string;
// TSConstructSignatureDeclaration
new <T>(): string;
}
// TSFunctionType
type Bar = <T>() => string;
// TSConstructorType
type Baz = new <T>() => string;Migration: If you have a customized plugin accessing properties of these TS nodes, make adjustments accordingly:
- For
node.parameters
in Babel 7, usenode.params
in Babel 8 - For
node.typeAnnotation
in Babel 7, usenode.returnType
in Babel 8
- For
-
Split
typeParameter
ofTSMappedType
(#16733).For a
TSMappedType
node, thetypeParameter
attribute is split intokey
andconstraint
attributes. This is to align the AST for TS nodes with@typescript-eslint
.// Example input
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(),
}Migration: If you have a customized plugin accessing
typeParameter
of aTSMappedType
node, usenode.key
andnode.constraint
in Babel 8.
-
Don't generate
TSParenthesizedType
unlesscreateParenthesizedExpression
is enabled(#9546, #12608)input.tstype T = ({});
// createParenthesizedExpression: true
TSParenthesizedType { typeAnnotation: TSTypeLiteral { members: [] } }
// createParenthesizedExpression: false
TSTypeLiteral { members: [] }Migration: If you need informations about parentheses, specify the
createParenthesizedExpression
parser option.babel.config.json{ "parserOpts": { "createParenthesizedExpression": true } }
When
createParenthesizedExpression
isfalse
, you can also usenode.extra.parenthesized
to detect whethernode
is wrapped in parentheses.
API Changes
All packages
-
Disallow importing internal files (#14013, #14179).
Migration: Use the exported API only. If you are relying on Babel internals, please open an issue and let us know.
@babel/core
-
Disallow using
babel.transform
,babel.transformFile
,babel.transformFromAst
,babel.parse
,babel.loadOptions
,babel.loadPartialConfig
andbabel.createConfigItem
synchronously (#11110, #12695, #15869).Migration: The API above require a callback argument. If you are not providing a callback, please use their sync versions:
babel.transformSync
,babel.transformFileSync
,babel.transformFromAstSync
,babel.parseSync
,babel.loadOptionsSync
,babel.loadPartialConfigSync
andbabel.createConfigItemSync
.
@babel/generator
-
Remove
CodeGenerator
class (#16126)Migration: In Babel 8 the undocumented
CodeGenerator
class has been removed, please use the default exportedgenerate
function instead.- new CodeGenerator(ast).generate()
+ generate(ast)
@babel/types
-
Reject invalid identifier names in
t.identifier
builder (#10917).babel-plugin.js// Empty string is an invalid identifier name
t.identifier("");Migration: Call
t.identifier
with a valid name. -
Remove
Super
from theExpression
alias (#14750).A
Super
node representssuper
in super callsuper()
and super propertysuper.foo
.super
can not be a standalone expression. In other words,t.isExpression(t.super())
will returnfalse
in Babel 8.Migration: Search usage of
t.isExpression
,t.assertsExpression
andExpression
alias in the plugin visitor, and if necessary, update the usage when you are handling super call and super property. For example,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")
))
}You don't have to update the usage if
super()
andsuper.foo
is not involved: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
))
}
-
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
selfClosing
argument fromt.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 fromt.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: The
Noop
node is not used. If you are depending on theNoop
node, please open an issue and talk about your use case. -
Initialize
indexers
,callProperties
andinternalSlots
in the nodeObjectTypeAnnotation
as an empty array int.objectTypeAnnotation
(#14465)Migration: In Babel 7 the builder
t.objectTypeAnnotation
initializes them asnull
, 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. Adapt to the new default value if you are depending on this. -
Reject negative and NaN/infinite numbers from
t.numericLiteral
(#15802)babel-plugin.js// NumericLiterals must be non-negative finite numbers.
t.numericLiteral(-1);Migration: Babel 7 silently ignores such invalid usage. Use
t.valueToNode(-1)
instead.
@babel/parser
-
Align Babel parser error codes between Flow and TypeScript (#13294)
Migration: The
error.code
forOptionalBindingPattern
is renamed asPatternIsOptional
. -
Remove
updateContext
field fromtokens[].type
returned 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 }Migration: This change probably won't affect your integration. The
tokens[].type
is an object storing meta information of a token as implementation details. -
Tokenize private name
#priv
as a singleprivateName
token (#13256)This change will affect your integration only when you are using
tokens: true
and are depending on the extratokens
AST output.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 }
// ]Migration: Adapt to the new
privateName
token. If you want to restore to the Babel 7 behaviour, manually process theprivateName
token into the#
token and thename
token (example). -
Tokenize string template as
templateNonTail
andtemplateTail
(#13919)This change will affect your integration only when you are using
tokens: true
and are depending on the extratokens
AST output.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" }
// ]Migration: Adapt to the new token design. If you want to restore to the Babel 7 behaviour, manually transform them to the Babel 7 tokens (example).
-
Remove
extra.shorthand
fromObjectProperty
nodes (#16521)Migration: Use
node.shorthand
rather thannode.extra.shorthand
.
@babel/traverse
-
Remove some
NodePath
methods (#16655)Migration:
hoist
,updateSiblingKeys
,call
,setScope
,resync
,popContext
,pushContext
,setup
,setKey
These methods are meant to be private so there is no real migration approach. But 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.is
,isnt
,has
,equals
Accesspath.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
block
argument fromScope#rename
(#15288)- rename(oldName: string, newName?: string, block?: t.Pattern | t.Scopable)
+ rename(oldName: string, newName?: string)Migration: In Babel 8 the third argument
block
is not used by the method. Consider remove it if you are depending onScope#rename
. -
Allow skipped
NodePath
s to be requeued (#13291)Notes:
NodePath#requeue()
can requeue a skipped NodePath. This is actually a bugfix, but it causes an infinite loop in the tdz implementation of@babel/plugin-transform-block-scoping
in Babel 7. So it may break other plugins as well.Migration: Adapt to the new behaviour. You can use
NodePath#shouldSkip
to check whether a NodePath has been skipped before callingNodePath#requeue()
. -
Remove methods starting with
_
(#16504)_assertUnremoved
_call
_callRemovalHooks
_containerInsert
_containerInsertAfter
_containerInsertBefore
_getKey
_getPattern
_getQueueContexts
_getTypeAnnotation
_markRemoved
_remove
_removeFromScope
_replaceWith
_resolve
_resyncKey
_resyncList
_resyncParent
_resyncRemoved
_verifyNodeListMigration: These methods are meant to be private so there is no real migration approach. But 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/compat-data
-
Remove
ios_saf
fromdata/native-modules.json
(#15068)Migration: Use
ios
instead. -
Rename stage 4 plugin entries from
proposal-*
totransform-*
inplugins.json
(#14976)Migration: For example, use
transform-class-properties
rather thanproposal-class-properties
. For a complete list of renamed plugin, see Packages Renames section of Babel 8 migration.
@babel/eslint-plugin
-
The
default
named exports has been removed (#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/helper-compilation-targets
-
isRequired
will not accept renamedproposal-
queries (#14976)my-babel-plugin.jsmodule.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
);
};Migration: Use the
transform-*
plugin name if the plugin is listed in the Packages Renames section of Babel 8 migration.
@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
requeueComputedKeyAndDecorators
instead. 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
includeUpdateExpression
from the default export (#15550)This change probabaly won't break your integration as
includeUpdateExpression
defaults totrue
in Babel 7. If you are usingincludeUpdateExpression: false
, adapt to the new behaviour.
@babel/highlight
-
Remove the
getChalk
function (https://github.com/babel/babel/pull/15812)If you need to use
chalk
, add it to your dependencies.
Plugin changes
-
Remove
getModuleName
from plugin pass (#12724)Migration: Use
.file.getModuleName
instead. For example,my-babel-plugin.jsmodule.exports = {
name: "my-babel-plugin",
visitor: {
Identifier(path, pass) {
- const moduleName = pass.getModuleName();
+ const moduleName = pass.file.getModuleName();
}
}
}
-
Remove
addImport
from plugin pass (#15576)Migration: This change probably will not affect your plugin as this method is already throwing an error in Babel 7. Use
addNamed
oraddDefault
from@babel/helper-module-imports
instead. -
Stop supporting fields as named exports (#15576)
Migration: This change disallows plugins declared from named exports, for example,
legacy-babel-plugin.jsexports.name = "legacy-babel-plugin";
exports.visitor = {
Identifier() {}
}find such patterns and migrate to the following patterns.
my-babel-plugin.cjsmodule.exports = {
name: "babel-plugin",
visitor: {
Identifier() {}
}
}