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() {}
}
}