Upgrade to Babel 7

    Because not every breaking change will affect every project, we’ve sorted the sections by the likelihood of a change breaking tests when upgrading.

    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 versions.

    Config Lookup Changes

    For more info, read our 6.x vs 7.x comparison.

    Babel has had issues previously with handling node_modules, symlinks, and monorepos. We’ve made some changes to account for this: Babel will stop lookup at the package.json boundary instead of looking up the chain. For monorepos we have added a new babel.config.js file that centralizes our config across all the packages (alternatively you could make a config per package). In 7.1, we’ve introduced a option for further lookup if necessary.

    The “env” preset has been out for more than a year now, and completely replaces some of the presets we’ve had and 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.

    We are removing the stage presets in favor of explicit proposal usage. Can check the stage-0 README for more migration steps.

    To do this automatically you can run (PR added here).

    Remove proposal polyfills in @babel/polyfill

    Based on similar thinking, we have removed the polyfill proposals from @babel/polyfill.

    Right now @babel/polyfill is mostly just an alias of core-js v2.

    Before it used to just be 2 imports:

    If you want to use proposals, you will need to import these independently. You should import them directly from the core-js package or another package on npm.

    e.g.

    1. // for core-js v2:
    2. import "core-js/fn/array/flat-map";
    3. // for core-js v3:
    4. import "core-js/features/array/flat-map";

    Below is a list of Stage < 3 proposal polyfills in core-js v2.

    1. // core-js v2
    2. // Stage 3
    3. import "core-js/fn/string/trim-left";
    4. import "core-js/fn/string/trim-right";
    5. import "core-js/fn/string/match-all";
    6. import "core-js/fn/array/flat-map";
    7. import "core-js/fn/array/flatten"; // RENAMED
    8. import "core-js/fn/global";
    9. // Stage 1
    10. import "core-js/fn/symbol/observable";
    11. import "core-js/fn/promise/try";
    12. import "core-js/fn/observable";
    13. // Stage 1 Math Extensions
    14. import "core-js/fn/math/clamp";
    15. import "core-js/fn/math/deg-per-rad";
    16. import "core-js/fn/math/degrees";
    17. import "core-js/fn/math/fscale";
    18. import "core-js/fn/math/iaddh";
    19. import "core-js/fn/math/isubh";
    20. import "core-js/fn/math/imulh";
    21. import "core-js/fn/math/rad-per-deg";
    22. import "core-js/fn/math/radians";
    23. import "core-js/fn/math/scale";
    24. import "core-js/fn/math/umulh";
    25. import "core-js/fn/math/signbit";
    26. // Stage 1 "of and from on collection constructors"
    27. import "core-js/fn/map/of";
    28. import "core-js/fn/set/of";
    29. import "core-js/fn/weak-map/of";
    30. import "core-js/fn/weak-set/of";
    31. import "core-js/fn/map/from";
    32. import "core-js/fn/set/from";
    33. import "core-js/fn/weak-map/from";
    34. import "core-js/fn/weak-set/from";
    35. // Stage 0
    36. import "core-js/fn/string/at";
    37. // Nonstandard
    38. import "core-js/fn/object/define-getter";
    39. import "core-js/fn/object/define-setter";
    40. import "core-js/fn/object/lookup-getter";
    41. // import "core-js/fn/map/to-json"; // Not available standalone
    42. // import "core-js/fn/set/to-json"; // Not available standalone
    43. import "core-js/fn/system/global";
    44. import "core-js/fn/error/is-error";
    45. import "core-js/fn/asap";
    46. // Decorator metadata? Not sure of stage/proposal
    47. import "core-js/fn/reflect/define-metadata";
    48. import "core-js/fn/reflect/delete-metadata";
    49. import "core-js/fn/reflect/get-metadata";
    50. import "core-js/fn/reflect/get-metadata-keys";
    51. import "core-js/fn/reflect/get-own-metadata";
    52. import "core-js/fn/reflect/get-own-metadata-keys";
    53. import "core-js/fn/reflect/has-metadata";
    54. import "core-js/fn/reflect/has-own-metadata";
    55. import "core-js/fn/reflect/metadata";

    Versioning/Dependencies

    Most plugins/top level packages now have a peerDependency on @babel/core.

    • babylon is now @babel/parser

    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).

    1. {
    2. - "presets": ["@babel/preset-react"],
    3. + "presets": ["@babel/react"], // this is equivalent
    4. - "plugins": ["@babel/transform-runtime"],
    5. + "plugins": ["@babel/plugin-transform-runtime"], // same
    6. }

    The most important change is finally switching all packages to (the folder names in the monorepo are not changed but the name in its package.json 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.

    1. module.exports = {
    2. presets: ["@babel/env"], // "@babel/preset-env"
    3. plugins: ["@babel/transform-arrow-functions"], // same as "@babel/plugin-transform-arrow-functions"
    4. };

    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)
    • 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.

    Some of the plugins had -es3- or -es2015- in the names, but these were unnecessary.

    @babel/plugin-transform-es2015-classes became @babel/plugin-transform-classes.

    "use strict" and this in CommonJS

    1. // input.js
    2. this;
    1. // output.js v6
    2. "use strict"; // assumed strict modules
    3. undefined; // changed this to undefined
    1. // output.js v7
    2. 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 , so we’ll want to revisit this before publishing).

    1. // input2.js
    2. import "a";
    1. // output.js v6 and v7
    2. "use strict";
    3. 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 of the React and Flow presets

    babel-preset-react has always included the flow plugin. This has caused a lot of issues with users that accidentally use flow syntax unintentionally due to a typo, or adding it in without typechecking with flow itself, resulting in errors.

    This issue was compounded when we decided to support TypeScript. 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 was easier to separate the presets entirely.

    Presets enable Babel to parse types provided by Flow / TypeScript (and other dialects / languages), then strip them out when compiling down to JavaScript.

    1. {
    2. - "presets": ["@babel/preset-react"]
    3. + "presets": ["@babel/preset-react", "@babel/preset-flow"] // parse & remove flow types
    4. + "presets": ["@babel/preset-react", "@babel/preset-typescript"] // parse & remove typescript types
    5. }

    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.

    1. {
    2. - "presets": "@babel/preset-env, @babel/preset-react"
    3. + "presets": ["@babel/preset-env", "@babel/preset-react"]
    4. }

    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

    1. babel --presets @babel/preset-env ../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.

    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.

    We have separated out Babel’s helpers from it’s “polyfilling” behavior in runtime. More details in the PR.

    now only contains the helpers, and if you need core-js you can use @babel/runtime-corejs2 and the option provided in the transform. For both you still need the

    Only Helpers

    1. {
    2. "plugins": ["@babel/plugin-transform-runtime"]
    3. }

    Helpers + polyfilling from core-js

    So if you need core-js support with transform-runtime, you would now pass the corejs option and use the @babel/runtime-corejs2 dependency instead of @babel/runtime.

    1. # install the runtime as a dependency
    2. npm install @babel/runtime-corejs2
    3. # install the plugin as a devDependency
    4. npm install @babel/plugin-transform-runtime --save-dev
    1. {
    2. "plugins": [
    3. - ["@babel/plugin-transform-runtime"],
    4. + ["@babel/plugin-transform-runtime", {
    5. + "corejs": 2,
    6. + }],
    7. ]
    8. }

    Spec Compliancy

    @babel/plugin-proposal-object-rest-spread

    A trailing comma cannot come after a RestElement in objects #290

    1. var {
    2. - ...y, // trailing comma is a SyntaxError
    3. + ...y
    4. } = { a: 1 };

    Since Object Spread defines new properties and Object.assign just sets them, Babel has changed the default behavior to be more spec compliant.

    1. // input
    2. z = { x, ...y };
    1. // v7 default behavior: ["proposal-object-rest-spread"]
    2. function _objectSpread(target) { ... }
    3. z = _objectSpread({
    4. x
    5. }, y);
    1. // Old v6 behavior: ["proposal-object-rest-spread", { "loose": true }]
    2. function _extends(target) { ... }
    3. z = _extends({
    4. x
    5. }, y);
    1. // Substitute for Object.assign: ["proposal-object-rest-spread", { "loose": true, "useBuiltIns": true }]
    2. z = Object.assign(
    3. {
    4. x,
    5. },
    6. );

    @babel/plugin-proposal-class-properties

    The default behavior is changed to what was previously “spec” by default

    1. // input
    2. class Bork {
    3. static a = "foo";
    4. y;
    5. }
    1. // v7 default behavior: ["@babel/plugin-proposal-class-properties"]
    2. var Bork = function Bork() {
    3. enumerable: true,
    4. writable: true,
    5. value: void 0,
    6. });
    7. };
    8. Object.defineProperty(Bork, "a", {
    9. enumerable: true,
    10. writable: true,
    11. value: "foo",
    12. });
    1. // old v6 behavior: ["@babel/plugin-proposal-class-properties", { "loose": true }]
    2. var Bork = function Bork() {
    3. this.y = void 0;
    4. };
    5. Bork.a = "foo";

    Split @babel/plugin-transform-export-extensions into the two renamed proposals

    This is a long time coming but this was finally changed.

    @babel/plugin-proposal-export-default-from

    1. export v from "mod";

    @babel/plugin-proposal-export-namespace-from

    Template Literals Revision updated low

    It causes Babel 6 to throw Bad character escape sequence (5:6).

    1. tag`\unicode and \u{55}`;

    This has been fixed in Babel 7 and generates something like the following:

    1. // default
    2. function _taggedTemplateLiteral(strings, raw) {
    3. return Object.freeze(
    4. Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })
    5. );
    6. }
    7. var _templateObject = /*#__PURE__*/ _taggedTemplateLiteral(
    8. [void 0],
    9. ["\\unicode and \\u{55}"]
    10. );
    11. tag(_templateObject);
    1. // loose mode
    2. function _taggedTemplateLiteralLoose(strings, raw) {
    3. strings.raw = raw;
    4. return strings;
    5. }
    6. var _templateObject = /*#__PURE__*/ _taggedTemplateLiteralLoose(
    7. [void 0],
    8. ["\\unicode and \\u{55}"]
    9. );
    10. tag(_templateObject);

    1. // input
    2. `foo${bar}`;
    1. // default v7 behavior: ["@babel/plugin-transform-template-literals"]
    2. "foo".concat(bar);
    1. // old v6 behavior: ["@babel/plugin-transform-template-literals", { "loose": true }]
    2. "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.

    1. {
    2. "plugins": [
    3. - "@babel/plugin-proposal-decorators"
    4. + ["@babel/plugin-proposal-decorators", { "legacy": true }]
    5. ]
    6. }

    NOTE: If you are using @babel/preset-stage-0 or @babel/preset-stage-1, which include this plugin, you must pass them the decoratorsLegacy option.

    @babel/plugin-proposal-pipeline-operator

    Newer proposals in flux will error by default and will require everyone to opt into a specific proposal while things are still < Stage 2. This is explained more in this post.

    1. {
    2. "plugins": [
    3. - "@babel/plugin-proposal-pipeline-operator"
    4. + ["@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" }]
    5. ]
    6. }

    Removed babel-plugin-transform-class-constructor-call

    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 for more information.

    1. class Point {
    2. constructor(x, y) {
    3. this.x = x;
    4. this.y = y;
    5. }
    6. - call constructor(x, y) {
    7. + static secondConstructor(x, y) {
    8. return new Point(x, y);
    9. }
    10. }
    11. let p1 = new Point(1, 2);
    12. - let p2 = Point(3, 4);
    13. + let p2 = Point.secondConstructor(3, 4);

    We merged babel-plugin-transform-async-to-module-method into the regular async plugin by just making it an option.

    1. {
    2. "plugins": [
    3. - ["@babel/transform-async-to-module-method"]
    4. + ["@babel/transform-async-to-generator", {
    5. + "module": "bluebird",
    6. + "method": "coroutine"
    7. + }]
    8. ]
    9. }

    babel

    Dropping the babel package low

    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

    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:

    1. npm install --save-dev @babel/register

    Upgrading with Mocha:

    1. + mocha --require @babel/register

    @babel/register will also now only compile files in the current working directly (was done to fix issues with symlinking).

    @babel/register options are now replaced instead of merged

    @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 none

    Currently there are 2 supported syntaxes (, and ;) in Flow Object Types.

    This change just makes babel-generator output , instead of ;.

    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 will return filename as an absolute path #8044

    @babel/preset-env

    mode will now automatically exclude the typeof-symbol transform (a lot of projects using loose mode were doing this).