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
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
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/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).
@babel/traverse
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()
.
@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() {}
}
}