7.8.0 Released: ECMAScript 2020, .mjs configuration files and @babel/cli improvements
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!
Highlights
#10811, #10817, #10819, #10843)
ECMAScript 2020 default support (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
:
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:
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.
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.
#10783 and #10903)
Support every configuration file extension (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 type | babel.config.__ | .babelrc.__ |
---|---|---|
.js | ✔️ Supported | ✔️ Supported |
.json | ❌ Not supported | ❔ Supported, with implicit extension |
ℹ️ 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 type | babel.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 type | babel.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.
#9144 and #10887)
New CLI options (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.
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:
$ 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:
#10899)
Extract targets parser and compat data from preset-env (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: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 orcore-js@2
polyfill is required. It's mostly generated fromcompat-table
, but we might add other data sources in the future. If you need data forcore-js@3
polyfills, you can usecore-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!
#10917)
Introduce opt-in stricter AST validation (@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:
// 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.