Skip to main content

7.5.0 Released: dynamic import and F# pipelines

· 7 min read

Today we are releasing Babel 7.5.0!

This release includes improved support for a few ECMAScript proposals: the F# variant of the Stage 1 pipeline operator and an official plugin for the Stage 4 dynamic import() proposal (along with preset-env support). It also has support for TypeScript namespaces (experimental) and for Browserslist's default query in preset-env.

You can read the whole changelog on GitHub.

Thanks to Wesley Wolfe, Martin Zlámal, Blaine Bublitz, Letladi Sebesho, Paul Comanici, Lidor Avitan, Artem Butusov, Sebastian Johansson, and Min ho Kim for their first PRs!

We are always looking for help, especially with triaging issues, reviewing pull requests and helping people on Slack. We are experimenting with the new triage role implemented by GitHub, and we want to recognize people from the community who will stand up and help us! 😉

A fantastic example of this are the newest additions to the Babel organization: Tan Li Hau, who has been a great help in triaging issues and fixing bugs, and Thiago Arrais, who helped in implementing the pipeline operator!

In other news, we just announced the start of our own podcast! If you missed it, please check out our post from yesterday!

Our work has made been possible also by our sponsors. We want to thank both Discord and clay for becoming Silver Sponsors on OpenCollective, as well as Linkedin for becoming a Silver Sponsor of Henry on GitHub!

Special thanks go to Handshake, a decentralized, permissionless naming protocol compatible with DNS, for donating $100,000 last year! As a part of their FOSS Community Grant, they pledged $10.2M to various open source communities like Apache, Debian, EFF, and Babel.

If you or your company want to support Babel and the evolution of JavaScript, but aren't sure how, you can sponsor us on 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 both fund our efforts in supporting the wide range of JavaScript users and taking ownership of the code. Reach out to Henry at henry@babeljs.io if you'd like to talk more!

F# pipeline operator (#9450 and #9984)

⚠️ The pipeline operator proposal is still at Stage 1, and thus its specification is still being defined.

This proposal has a few variants that are being thought out. By testing this plugin, you can help the proposal authors gather feedback about how pipelines could work. But also note that refactoring will be required if the semantics change throughout the proposal process (and they will).

Since version 7.3.0, Babel has supported the Smart variant of the pipeline operator proposal, and the "minimal" variant since 7.0.0-beta.

Thanks to the joint efforts of Thiago Arrais and James DiGioia, you can now also test the "# variant! If you have thoughts or comments about this specific proposal variant, you can reach out to James.

How is the F# variant different from the Smart one? Instead of having the concept of "topic references" (#), arrow functions are used instead. This has the advantage of being more similar to current JavaScript, at the cost of a slightly less concise syntax.

Current JavaScriptF# pipelineSmart pipeline
JavaScript
let newScore = boundScore(
0,
100,
add(7, double(person.score))
);
JavaScript
let newScore = person.score
|> double
|> n => add(7, n)
|> n => boundScore(0, 100, n);

JavaScript
let newScore = person.score
|> double
|> add(7, #)
|> boundScore(0, 100, #);

Although the two proposals aren't dependent on one another or being developed as a single proposal, you can use F# pipelines alongside with partial application (supported since Babel 7.4.0):

JavaScript
let newScore = person.score
|> double
|> add(7, ?)
|> boundScore(0, 100, ?);

Note that, while it may look the same as the "Smart" pipeline variant, the partial application proposal only supports ? in function call parameters. This means that, for example, person |> #.score is a valid "Smart" pipeline whose F# equivalent must use an arrow function: person |> p => p.score.

The F# pipeline operator is also different regarding how await is handled:

Current JavaScriptF# pipelineSmart pipeline
JavaScript
let id = (
await (
await fetch(url)
).json()
).ID;
JavaScript
let newScore = fetch(url)
|> await
|> r => r.json()
|> await
|> obj => obj.ID;
JavaScript
let newScore = fetch(url)
|> await #
|> #.json()
|> await #
|> #.ID;

If you want to test this new proposal variant, you can add @babel/plugin-proposal-pipeline-operator to your Babel configuration:

JavaScript
module.exports = {
plugins: [
["@babel/proposal-pipeline-operator", { proposal: "fsharp" }]
]
};

You can also try it out in the repl, by enabling the "Stage 1" preset.

Dynamic import (#9552 and #10109)

Although Babel has had support for parsing dynamic imports import(source) for a long time, there hasn't been a consistent way of transforming it.

  • If you used webpack or rollup, you would only include @babel/plugin-syntax-dynamic-import and not transform it with Babel
  • If you used Node, you could use the babel-plugin-dynamic-import-node plugin to transform it
  • If you used SystemJS, @babel/plugin-transform-modules-systemjs in conjunction with @babel/plugin-syntax-dynamic-import transformed it without explicitly enabling a transform plugin for import()

Since the dynamic import proposal has been recently merged into the main specification, we have decided to unify these use-cases under a single entry point: @babel/plugin-proposal-dynamic-import. This plugin must be used alongside one of the module transform plugins because Babel needs to know which module loading system you are targeting. When targeting CommonJS, it internally delegates to babel-plugin-dynamic-import-node.

For example, this is a valid configuration:

JavaScript
module.exports = {
plugins: [
"@babel/plugin-proposal-dynamic-import",
"@babel/plugin-transform-modules-amd"
]
};

While this isn't:

JavaScript
module.exports = {
plugins: [
"@babel/plugin-proposal-dynamic-import"
]
};

If you want to only allow parsing of import() expressions without transforming them, you can just include the @babel/plugin-syntax-dynamic-import package.

If you are using @babel/preset-env, dynamic import support will be enabled by default. You don't need to worry about webpack or rollup support, since both babel-loader and rollup-plugin-babel automatically disable the Babel transform to allow the bundler to handle it correctly.

defaults browserslist query in @babel/preset-env (#8897)

When @babel/preset-env is not passed any targets, it runs every syntax transform on your code (emulating the now deprecated babel-preset-latest).

To support this behavior, we had to work around the fact that Browserslist itself has default choices. This caused @babel/preset-env to not allow usage of the default query.

@babel/preset-env now supports the defaults query when passing targets directly to the preset:

JavaScript
module.exports = {
presets: [
["@babel/preset-env", {
targets: { browsers: "defaults" }
}]
]
};

You can also set it using a .browserslistrc file, which is also used by other tools like Autoprefixer or Stylelint.

The default behavior of @babel/preset-env is still to compile everything, but we might switch it in Babel 8 to use this defaults query.

Experimental TypeScript namespaces support (#9785)

Until now, namespaces were the second biggest TypeScript feature not supported by Babel (the first one is type-checking! 😛). Thanks to the work done by community member Wesley Wolfe, you can now enable experimental support for them in the TypeScript plugin, using the allowNamespaces option of @babel/plugin-transform-typescript:

JavaScript
module.exports = {
plugins: [
["@babel/plugin-transform-typescript", {
allowNamespaces: true
}]
]
}

Then, you can use namespaces in your code:

JavaScript
namespace Validation {
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;

export class LettersOnlyValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
}

⚠️ Warning ⚠️

When TypeScript support was initially added to Babel, namespaces were not included since they require type information that only a full TypeScript compiler and type-checker can provide. For this reason, this current (experimental) support has some limitations:

  • Namespaces can only export immutable bindings
  • When merging multiple namespaces with the same name, their scope isn't shared

You can find the full list of caveats in the @babel/plugin-transform-typescript documentation.