Upgrade to Babel 7
Refer users to this document when upgrading to Babel 7.
Help edit this file here
Because not every breaking change will affect every project, we've sorted the sections by the likelihood of a change breaking tests when upgrading.
All of Babel
Support for Node.js 0.10, 0.12, 4 and 5 has been dropped #5025, #5041, #7755, #5186
We highly encourage you to use a newer version of Node.js (LTS v8) since the previous versions are not maintained. See nodejs/LTS for more information.
This just means Babel itself won't run on older versions of Node. It can still output code that runs on old Node.
Yearly Preset Deprecations
The "env" preset has been out for more than a year now, and completely replaces some of the presets we've had/suggested earlier.
babel-preset-es2015
babel-preset-es2016
babel-preset-es2017
babel-preset-latest
- A combination of the above ^
These presets should be substituted with the "env" preset.
Versioning/Dependencies
Most plugins/top level packages now have a peerDependency
on @babel/core
.
Package Renames
You can still use the shorthand version of a package name (remove the preset-
or plugin-
) in the config, but I'm choosing to use the whole package name for clarity (maybe we should just remove that, given it doesn't save that much typing anyway).
{
- "presets": ["@babel/preset-react"],
+ "presets": ["@babel/react"], // this is equivalent
- "plugins": ["@babel/transform-runtime"],
+ "plugins": ["@babel/plugin-transform-runtime"], // same
}
Scoped Packages
The most important change is finally switching all packages to scoped packages. (the folder names in the monorepo are not changed but the package.name is)
This means there will be no more issues with accidental/intentional name squatting, a clear separation from community plugins, and a simpler naming convention.
Your dependencies will need to be modified like so:
babel-cli
-> @babel/cli
. For us, we basically started by replacing babel-
with @babel/
.
Use in the config
You can still use the shorthand way of specifying a preset or plugin. However because of the switch to scoped packages, you still have to specify the @babel/
just like if you had your own preset to add to the config.
module.exports = {
"presets": ["@babel/env"], // "@babel/preset-env"
"plugins": ["@babel/transform-arrow-functions"] // same as "@babel/plugin-transform-arrow-functions"
};
Switch to -proposal-
for TC39 Proposals
This means any plugin that isn't in a yearly release (ES2015, ES2016, etc) should be renamed to -proposal
. This is so we can better signify that a proposal isn't officially in JavaScript.
Examples:
@babel/plugin-transform-function-bind
is now@babel/plugin-proposal-function-bind
(Stage 0)@babel/plugin-transform-class-properties
is now@babel/plugin-proposal-class-properties
(Stage 3)
This also means that when a proposal moves to Stage 4, we should rename the package.
Remove the year from package names
Some of the plugins had -es3-
or -es2015-
in the names, but these were unncessary.
@babel/plugin-transform-es2015-classes
became @babel/plugin-transform-classes
.
"use strict"
and this
in CommonJS
Babel 6's transformations for ES6 modules ran indiscriminantly on whatever files it was told to process, never taking into account if the file actually had ES6 imports/exports in them. This had the effect of rewriting file-scoped references to this
to be undefined
and inserting "use strict"
at the top of all CommonJS modules that were processed by Babel.
// input.js
this;
// output.js v6
"use strict"; // assumed strict modules
undefined; // changed this to undefined
// output.js v7
this;
This behavior has been restricted in Babel 7 so that for the transform-es2015-modules-commonjs
transform, the file is only changed if it has ES6 imports or exports in the file. (Editor's note: This may change again if we land https://github.com/babel/babel/issues/6242, so we'll want to revisit this before publishing).
// input2.js
import 'a';
// output.js v6 and v7
'use strict';
require('a');
If you were relying on Babel to inject "use strict"
into all of your CommonJS modules automatically, you'll want to explicitly use the transform-strict-mode
plugin in your Babel config.
Separation between the React and Flow presets
babel-preset-react
has always included the flow plugin automatically from the beginning. This has actually caused a lot of issues with users that accidently use flow
syntax without intending due to a typo, or adding it in without typechecking with flow
itself, resulting in errors.
This became further of an issue after we decided to support TypeScript with the help of the TS team. If you wanted to use the react and typescript presets, we would have to figure out a way to turn on/off the syntax automatically via file type or the directive. In the end it seemed easiest to just separate the presets entirely.
So now the react preset and the flow preset are separated.
{
- "presets": ["@babel/preset-react"]
+ "presets": ["@babel/preset-react", "@babel/preset-flow"] // remove flow types
+ "presets": ["@babel/preset-react", "@babel/preset-typescript"] // remove typescript types
}
Option parsing
Babel's config options are stricter than in Babel 6.
Where a comma-separated list for presets, e.g. "presets": 'es2015, es2016'
technically worked before, it will now fail and needs to be changed to an array #5463.
Note this does not apply to the CLI, where --presets es2015,es2016
will certainly still work.
{
- "presets": "@babel/preset-env, @babel/preset-react"
+ "presets": ["@babel/preset-env", "@babel/preset-react"]
}
Plugin/Preset Exports
All plugins/presets should now export a function rather than an object for consistency [via babel/babel#6494]. This will help us with caching.
Resolving string-based config values
In Babel 6, values passed to Babel directly (not from a config file), were resolved relative to the files being compiled, which led to lots of confusion.
In Babel 7, values are resolved consistently either relative to the config file that loaded them, or relative to the working directory.
For presets
and plugins
values, this change means that the CLI will behave nicely in cases such as
babel --presets @babel/preset-es2015 ../file.js
Assuming your node_modules
folder is in .
, in Babel 6 this would fail because the preset could not be found.
This change also affects only
and ignore
which will be expanded on next.
only
and ignore
patterns
Path-based In Babel 6, only
and ignore
were treated as a general matching string, rather than a filepath glob. This meant that for instance *.foo.js
would match ./**/*.foo.js
, which was confusing and surprising to most users.
In Babel 7, these are now treated as path-based glob patterns which can either be relative or absolute paths. This means that if you were using these patterns, you'll probably need to at least add a **/
prefix to them now to ensure that your patterns match deeply into directories.
only
and ignore
patterns do still also work for directories, so you could also use only: './tests'
to only compile files in your tests
directory, with no need to use **/*.js
to match all nested files.
Babel's CLI commands
The --copy-files
argument for the babel
command, which tells Babel to copy all files in a directory that Babel doesn't know how to handle, will also now copy files that failed an only
/ignore
check, where before it would silently skip all ignored files.
@babel/node
The babel-node
command in Babel 6 was part of the babel-cli
package. In Babel 7, this command has been split out into its own @babel/node
package, so if you are using that command, you'll want to add this new dependency.
@babel/preset-stage-3
Remove Stage 4 plugins from Stage 3 #5126
These plugins were moved into their yearly presets after moving to Stage 4:
babel-plugin-syntax-trailing-function-commas
(babel-preset-es2017
)babel-plugin-transform-async-to-generator
(babel-preset-es2017
)babel-plugin-transform-exponentiation-operator
(babel-preset-es2016
)
Part of the reason we wanted to remove/deprecate stage presets in the first place are because of this issue. Whenever a proposal gets to Stage 4, it should technically be removed from the Stage 3 preset but it is a breaking change. Because all proposals are at risk (almost guranteed) to have breaking changes, it's the only parts of the Babel repo that would regularly have major version bumps (unless we do a 0.x versioning system which is basically the same thing). At the same time, we aren't doing the best job of signaling what each Stage means and the kinds of precautions you may want to take when using a proposal, especially in production.
Spec Compliancy
@babel/plugin-proposal-object-rest-spread
A trailing comma cannot come after a RestElement in objects #290
var {
- ...y, // trailing comma is a SyntaxError
+ ...y
} = { a: 1 };
Since Object Spread defines new propeties and
Object.assign
just sets them, Babel has changed the default behavior to be more spec compliant.
// input
z = { x, ...y };
// v7 default behavior: ["proposal-object-rest-spread"]
function _objectSpread(target) { ... }
z = _objectSpread({
x
}, y);
// Old v6 behavior: ["proposal-object-rest-spread", { "loose": true }]
function _extends(target) { ... }
z = _extends({
x
}, y);
// Substitute for Object.assign: ["proposal-object-rest-spread", { "loose": true, "useBuiltIns": true }]
z = Object.assign({
x
}, y);
@babel/plugin-proposal-class-properties
The default behavior is changed to what was previously "spec" by default
// input
class Bork {
static a = 'foo';
y;
}
// v7 default behavior: ["@babel/plugin-proposal-class-properties"]
var Bork = function Bork() {
Object.defineProperty(this, "y", {
enumerable: true,
writable: true,
value: void 0
});
};
Object.defineProperty(Bork, "a", {
enumerable: true,
writable: true,
value: 'foo'
});
// old v6 behavior: ["@babel/plugin-proposal-class-properties", { "loose": true }]
var Bork = function Bork() {
this.y = void 0;
};
Bork.a = 'foo';
@babel/plugin-transform-export-extensions
into the two renamed proposals
Split This is a long time coming but this was finally changed.
@babel/plugin-proposal-export-default-from
export v from 'mod';
@babel/plugin-proposal-export-namespace-from
export * as ns from 'mod';
@babel/plugin-transform-template-literals
Template Literals Revision updated #5523
See the proposal for Template Literals Revision.
It cause Babel 6 to throw Bad character escape sequence (5:6)
.
tag`\unicode and \u{55}`;
This has been fixed in Babel 7 and generates something like the following:
// default
function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
var _templateObject = /*#__PURE__*/ _taggedTemplateLiteral([void 0], ["\\unicode and \\u{55}"]);
tag(_templateObject);
// loose mode
function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; }
var _templateObject = /*#__PURE__*/ _taggedTemplateLiteralLoose([void 0], ["\\unicode and \\u{55}"]);
tag(_templateObject);
Default to previous "spec" mode for regular template literals
// input
`foo${bar}`;
// default v7 behavior: ["@babel/plugin-transform-template-literals"]
"foo".concat(bar);
// old v6 behavior: ["@babel/plugin-transform-template-literals", { "loose": true }]
"foo" + bar;
@babel/plugin-proposal-decorators
In anticipation of the new decorators proposal implementation, we've decided to make it the new default behavior. This means that to continue using the current decorators syntax/behavior, you must set the legacy
option as true
.
{
"plugins": [
- "@babel/plugin-proposal-decorators"
+ ["@babel/plugin-proposal-decorators", { "legacy": true }]
]
}
NOTE: If you are using
@babel/preset-stage-0
or@babel/preset-stage-1
, which include this plugin, you must pass them thedecoratorsLegacy
option.
babel-plugin-transform-class-constructor-call
Removed babel-plugin-transform-class-constructor-call has been removed #5119
TC39 decided to drop this proposal. You can move your logic into the constructor or into a static method.
See /docs/plugins/transform-class-constructor-call/ for more information.
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
- call constructor(x, y) {
+ static secondConstructor(x, y) {
return new Point(x, y);
}
}
let p1 = new Point(1, 2);
- let p2 = Point(3, 4);
+ let p2 = Point.secondConstructor(3, 4);
@babel/plugin-async-to-generator
We merged babel-plugin-transform-async-to-module-method
into the regular async plugin by just making it an option.
{
"plugins": [
- ["@babel/transform-async-to-module-method"]
+ ["@babel/transform-async-to-generator", {
+ "module": "bluebird",
+ "method": "coroutine"
+ }]
]
}
babel
Dropping the
babel
package #5293
This package currently gives you an error message to install babel-cli
instead in v6.
I think we can do something interesting with this name though.
@babel/register
babel-core/register.js
has been removed #5132
The deprecated usage of babel-core/register
has been removed in Babel 7; instead use the standalone package @babel/register
.
Install @babel/register
as a new dependency:
npm install --save-dev @babel/register
Upgrading with Mocha:
- mocha --compilers js:babel-core/register
+ mocha --compilers js:@babel/register
@babel/register
will also now only compile files in the current working directly (was done to fix issues with symlinking).
@babel/generator
Dropping the
quotes
option #5154]
If you want formatting for compiled output you can use recast/prettier/escodegen/fork babel-generator.
This option was only available through babel-generator
explicitly until v6.18.0 when we exposed parserOpts
and generatorOpts
. Because there was a bug in that release, no one should've used this option in Babel itself.
Dropping the
flowUsesCommas
option #5123
Currently there are 2 supported syntaxes (,
and ;
) in Flow Object Types.
This change just makes babel-generator output ,
instead of ;
.
@babel/core
Remove
babel-core/src/api/browser.js
#5124
babel-browser
was already removed in 6.0. If you need to use Babel in the browser or a non-Node environment, use babel-standalone.
@babel/preset-env
loose
mode will now automatically exclude the typeof-symbol
transform (a lot of projects using loose mode were doing this).