Skip to main content

7.8.0 Released: ECMAScript 2020, .mjs configuration files and @babel/cli improvements

· 8 min read

This is the first release of the year! 🎉

Babel 7.8.0 supports the new ECMAScript 2020 features by default: you don't need to enable individual plugins for nullish coalescing (??), optional chaining (?.) and dynamic import() anymore with preset-env.

We also finished aligning our different configuration files with the formats natively supported by Node.js, a process that we started in the 7.7.0 release.

Lastly, Babel's CLI now supports two new options: --out-file-extension and --copy-ignored.

You can read the whole changelog on GitHub.


Shoutout to Abdul Ali, Jack Isherwood, Jayen Ashar, James Beavers, Klaus Meinhardt, Oleksandr Fediashov, Siddhant N Trivedi, Tsubasa Nakayama, Yordis Prieto and ZYSzys for their first PRs!

We also want to thank Thomas Smith for volunteering to help us maintain the important babel-sublime syntax highlighter plugin, and welcome Raja Sekar, our newest addition to the Babel organization!

If you or your company wants to support Babel and the evolution of JavaScript, but aren't sure how, you can donate to us on our Open Collective and, better yet, work with us on the implementation of new ECMAScript proposals directly! As a volunteer-driven project, we rely on the community's support to fund our efforts in supporting the wide range of JavaScript users. Reach out at team@babeljs.io if you'd like to discuss more!

We recently published a funding post detailing our funding plans and our goals. Check it out!

ECMAScript 2020 default support (#10811, #10817, #10819, #10843)

During the last meeting, TC39 moved both the nullish coalescing and optional chaining proposals to Stage 4!

The nullish coalescing operator allows you to provide a fallback value when an expression evaluates to null or undefined:

JavaScript
const name = person.fullName ?? "Anonymous";
console.log(`Hello, ${name}!`);

This is similar to how the logical OR (||) operator works. The difference is that while || checks for "falsy" values (i.e. undefined, null, false, 0, 0n and ""), ?? only checks for "nullish" values. This better matches the "value not provided" mental model, and works better with possibly falsy, but valid, values:

JavaScript
const element = { index: 0, value: "foo" };

const index = element.index ?? -1; // 0 :D
const index = element.index || -1; // -1 :(

The optional chaining proposal uses the same concept of "nullish values", allowing optional property accesses on values which could be nullish. It also supports optional function calls and computed properties.

JavaScript
const city = person.address?.city; // person.address could be not defined
const isNeighbor = person.address?.isCloseTo(me);

person.sayHayUsing?.("Twitter"); // The person.sayHayUsing method could be not defined

You can now safely use these new features in your code! If you are already using @babel/preset-env, you can use these two operators and they will be compiled based on your targets, just like any other ECMAScript feature. If you were using the @babel/plugin-proposal-nullish-coalescing-operator or @babel/plugin-proposal-optional-chaining directly, you can remove them from your config:

{
"presets": [
["@babel/env", { "targets": ["last 2 versions"] }]
],
"plugins": [
- "@babel/proposal-optional-chaining",
- "@babel/proposal-nullish-coalescing-operator"
]
}

These features are now also enabled by default in @babel/parser: if you were using it directly, you can remove the nullishCoalescingOperator and optionalChaining parser plugins. We also enabled parsing for dynamic import() (which has been included in @babel/preset-env since v7.5.0), so you can safely remove the dynamicImport plugin.

Support every configuration file extension (#10783 and #10903)

Babel 6 supported a single, JSON-based, configuration file: .babelrc.

In Babel 7.0.0, we introduced babel.config.js (which has different resolution logic) and .babelrc.js. JavaScript config files can be useful for scenarios needing higher flexibility. This was the situation:

Node.js file typebabel.config.__.babelrc.__
.js✔️ Supported✔️ Supported
.json❌ Not supported❔ Supported, with implicit extension
tip

We strongly recommend reading about the differences between babel.config.js and .babelrc.js!

More recently, Node.js 13.2.0 was released, adding support for native ECMAScript modules and the .cjs and .mjs file extensions. In Babel 7.7.0 we added support for .cjs config files to allow users to enable "type": "module" in their package.json without breaking Babel, as well as support for babel.config.json, which allows for static project-wide configuration.

Node.js file typebabel.config.__.babelrc.__
.js✔️ Supported when "type": "module" is not enabled✔️ Supported when "type": "module" is not enabled
.json✔️ Supported❔ Supported, with implicit extension
.cjs✔️ Supported✔️ Supported
.mjs❌ Not supported❌ Not supported

This release aligns Babel with the file types natively supported by Node.js by allowing .babelrc.json, babel.config.mjs, and .babelrc.mjs.

Node.js file typebabel.config.__.babelrc.__
.js✔️ Supported✔️ Supported
.json✔️ Supported✔️ Supported
.cjs✔️ Supported✔️ Supported
.mjs✔️ Supported✔️ Supported

Please remember that ECMAScript modules are asynchronous: that's why, for example, you can't require() them and instead have to use import(), which returns a promise.

For these reasons, they can only be used when calling Babel via the promise-based or callback-based entry points. They already work with @babel/cli, babel-loader and gulp-babel, and they will work with the next release of rollup-plugin-babel. Note that they are not supported by babel-eslint yet.

New CLI options (#9144 and #10887)

We added two new flags to @babel/cli: --copy-ignored and --out-file-extension.

--copy-ignored can be used to copy files that are not transpiled by Babel, either because they are ignored using the --ignore CLI option, or because "ignore" is set in a configuration file.

caution

To maintain backward compatibility, in Babel 7.8.4 the default value of the --copy-ignored option has been changed to true. If you want to disable it, you can use --no-copy-ignored.

This is similar to how the --copy-files option works, but --copy-files is meant to copy anything which is not transpiled because it isn't a JavaScript file (for example, .css or .json), rather than explicitly ignored files.

--out-file-extension can be used to configure the extension of the files generated by Babel. For example, if you are transpiling .js files containing native ECMAScript modules in Node.js and want to generate CommonJS files, you might need to use the .cjs extension:

Shell
$ babel src --out-dir lib-cjs --out-file-extension cjs

Preparing for Babel 8

We are starting to work on the Babel 8.0.0 release in our umbrella issue: #10746.

Babel 8 will only contain breaking changes: we will release a minor version the same day, containing all the bug fixes and new features that would otherwise be released in 8.0.0.

While we don't anticipate a huge migration path, there are two issues which we want to bring to your attention:

Extract targets parser and compat data from preset-env (#10899)

Various 3rd party presets are currently using @babel/preset-env's internal logic to parse compilation targets or to retrieve information about necessary plugins and polyfills.

We have decided to officially support these two use cases by providing two new public packages:

  • @babel/helper-compilation-targets, which exports a function to normalize the specified targets and a few other related utilities:

    JavaScript
    import getTargets from "@babel/helper-compilation-targets";

    getTargets({
    browsers: ["last 2 chrome versions"],
    node: 10,
    }) ==
    {
    chrome: "77.0.0",
    node: "10.0.0",
    };
  • @babel/compat-data, which contains a collection of JSON files where we store all the browsers versions for which each plugin or core-js@2 polyfill is required. It's mostly generated from compat-table, but we might add other data sources in the future. If you need data for core-js@3 polyfills, you can use core-js-compat.

We plan to disallow using internal files starting from Babel 8. If you are relying on other internal APIs, please let us know!

Introduce opt-in stricter AST validation (#10917)

@babel/types already performs many checks to ensure that the AST you are building is valid. For example, this code will throw because you can't use a statement in place of an expression:

JavaScript
// foo = if (true) {}

t.assignmentExpression(
"=",
t.identifier("foo"),
t.ifStatement(t.booleanLiteral(true), t.blockStatement([]))
);

We are introducing stricter validation to prevent even more invalid ASTs: not only from a tree shape point of view but also ensuring that nodes in the correct position carry valid information. For example, starting from Babel 8 t.identifier("123") will be disallowed, because 123 is not a valid identifier.

We can't enable these checks in Babel 7.8.0 because the risk of breaking existing plugins is too high, but we highly encourage you to enable these stricter checks using the BABEL_TYPES_8_BREAKING=true environment variable and open issues (or better, PRs!) to fix the plugins that you are using which won't work with Babel 8.