If you didn't know already, we're planning on releasing a 7.0 version soon π ! Work on it actually started back in February, when I just wanted to make a release to drop Node 0.10/0.12 support and remove babel-runtime and various other code. And since then, we've done releases up to alpha.20
.
We're going to update this post throughout the beta releases
Since we're still just a volunteer project, it's been difficult for most of the team to stay focused and motivated to make all these changes and continue to maintain a project that so many companies, bootcamps, and tools rely on so much. But in the meantime we've made a lot of progress: weekly meetings/notes, participating as invited guests at TC39 for the last few meetings, facilitating in both RGSoC and GSoC, and creating an Open Collective.
Upgradingβ
Upgrading for most projects should be as simple as updating your
package.json
deps to7.0.0-beta.0
. For the whole time we've been working on 7.0, we've been using it in Babel itself (so meta) and at my workplace at Behance.
We will be pinning all dependencies to exact versions until the official release.
{
"devDependencies": {
"babel-cli": "7.0.0-beta.0"
}
}
Specific packages:
Details
babel packages in the monorepo should all be >= 7.0.0-beta.0
babel-preset-env should be at least 2.0.0-beta.0
babel-eslint can be >= 8.0.0
babel-loader should be >= 7.0.0 (out of beta since it uses babel-core as a peerDependency)
grunt-babel can be >= 7.0.0
gulp-babel can be >= 7.0.0
rollup-plugin-babel can be >= 3.0.2
Please check out our upgrade guide and other guide specifically for tool authors which we will also be updating as necessary.
I'd like to go over some notable changes for our first beta release (it's still a lot smaller in scope in terms of breaking changes than the previous 6.0 release).
Re-iterating Project Goalsβ
Before we go into that, I just want to repeat again what the purpose of Babel is.
Since Babel has been renamed from 6to5, browsers have been implementing more of the spec and users are more comfortable with using the latest syntax/build tooling. It shouldn't be surprisingly however that Babel's goals haven't changed much.
Our two goals are hand in hand:
- Help developers transform new syntax into backwards compatible code (abstract browser support away)
- Be a bridge to help TC39 get feedback on new ECMAScript proposals and for the community to have a say in the future of the language.
Thus, I think it's an understatement to say that Babel is a vital part of the JavaScript community (almost 10 million downloads a month of babel-core
) and sorely needs its support. (The only talks I've tried to give are about this point: JSConf EU, React Rally, TC39). I said recently: "What happens if Babel dies"? What happens when the current group of people interested in this project get bored/burned out/move on to other things? (What if it's already happened?). Are we going to do something about it? I don't want to just ask you to help us, you already are us as users of the project.
Ok then, let's talk about some changes!
Drop Support for Unmaintained Node Versions: 0.10, 0.12, 5 (#4315)β
Progress in OSS projects often comes at the cost of upgrading for its users. Because of this, we've always been hesitant in making the choice to introduce a major version bump/breaking changes. By dropping unsupported versions of Node, we can not only make a number of improvements to the codebase, but also upgrade dependencies and tools (ESLint, Yarn, Jest, Lerna, etc).
π Proposal Updates/Spec Compliancyβ
AKA the only things most of you care about π
Philosophy (Proposals: spec, loose, default behavior)β
We've created a new repo: babel/proposals to track our progress on the various TC39 Proposals and meetings.
I also added a section about how we accept new proposals. Our basic thinking is that we will start accepting PRs for anything a TC39 champion is going to present (Stage 0). And we will update them (with your help!) when the spec changes.
Naturally, we will take the opportunity to be as spec compliant as possible (within reasonable speed, etc) as the default behavior. This means if you need a faster/smaller build, you should use the loose
option which will purposely disregard certain spec changes like runtime checks and other edge cases. The reason why it is opt-in is because we expect you should know what you are doing, while others should be able to seamlessly upgrade babel-preset-env
to use the native version of each syntax or stop using Babel entirely and have no issues.
Stage 3: Class Properties (from Stage 2)β
babel-plugin-transform-class-properties
: the default behavior is now what was previously the "spec" option, which usesObject.defineProperty
instead of simple assignment.
This currently has the effect of breaking the legacy decorators plugin (which we made the "transform-decorators" plugin in 7.0) if you try to decorate a class property. You'll need to use the
loose
option to be compatible with the version of decorators in the transform until we release the Stage 2 decorators plugin.
Private fields are WIP: #6120
Input
class Bork {
static a = 'foo';
x = 'bar';
}
Output (default)
class Bork {
constructor() {
Object.defineProperty(this, "x", {
configurable: true,
enumerable: true,
writable: true,
value: 'bar'
});
}
};
Object.defineProperty(Bork, "a", {
configurable: true,
enumerable: true,
writable: true,
value: 'foo'
});
Output (loose mode)
class Bork {
constructor() {
this.x = 'bar';
}
};
Bork.a = 'foo';
Stage 3: Object Rest Spread (from Stage 2)β
babel-plugin-transform-object-rest-spread
: And now the plugin handles non-string keys (ex: Number/Symbol)
Input
// Rest Properties
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }
// Spread Properties
let n = { x, y, ...z };
console.log(n); // { x: 1, y: 2, a: 3, b: 4 }
Also disallowed
var { ...{ x } } = obj;
var { ...[ y ] } = obj;
Stage 3: Optional Catch Binding (new)β
babel-plugin-transform-optional-catch-binding
: allow developers to use try/catch without creating an unused binding.
Input
try {
throw 0;
} catch {
doSomethingWhichDoesNotCareAboutTheValueThrown();
}
Output
try {
throw 0;
} catch (_unused) {
doSomethingWhichDoesNotCareAboutTheValueThrown();
}
Stage 3: Unicode Property Regex (new)β
babel-plugin-transform-unicode-property-regex
: compile Unicode property escapes (\p{β¦}
and\P{β¦}
) in Unicode regular expressions to ES5 or ES6 that works in todayβs environments.
Input
var regex = /\p{ASCII_Hex_Digit}/u;
Output
var regex = /[0-9A-Fa-f]/;
Stage 3: BigInt (new, unfinished)β
babel-plugin-transform-bigint
: #6015. This won't be included in the Stage presets because it would be slow to wrap all operators.
Input
50000n + 60n;
Output
import babelCheckBinaryExpressions from "babel-check-binary-expressions";
babelCheckBinaryExpressions(new BigInt("50000"), new BigInt("60"), "+");
Stage 3: Dynamic Import (from Stage 2)β
babel-plugin-syntax-dynamic-import
: You only need to parse the syntax since tools like Webpack can handle the transformation in place of Babel. There is also a plugin for Node
Input
const testModule = import('test-module');
Stage 2: import.meta
(syntax only)β
A meta property that is only syntactically valid in modules, meant for meta-information about the currently running module provided by the host environment.
Input
const size = import.meta.scriptElement.dataset.size || 300;
Stage 2: Numeric Separators (new)β
babel-plugin-transform-numeric-separator
: make numeric literals more readable by creating a visual separation (a_
) between groups of digits.
Input
1_000_000_000
0b1010_0001_1000_0101
0xA0_B0_C0
Output
1000000000
0b1010000110000101
0xA0B0C0
Stage 2: Decorators (from Stage 1), still WIPβ
Disallowed
// no computed decorator keys
@dec[foo]
class A {}
// no parameter decorators (a separate proposal)
class Foo {
constructor(@foo x) {}
}
// no decorators on object methods
var o = {
@baz
foo() {}
}
// decorator cannot be attached to the export
@foo
export default class {}
Valid
// decorators with a call expression
@foo('bar')
class A {
// decorators on computed methods
@autobind
[method](arg) {}
// decorators on generator functions
@deco
*gen() {}
// decorators with a member expression
@a.b.c(e, f)
m() {}
}
// exported decorator classes
export default @foo class {}
Unsupported (WIP)
// decorated class properties
class A {
@dec name = 0
}
Stage 2: function.sent
(new)β
babel-plugin-transform-function-sent
: compile thefunction.sent
meta property, used inside generator functions
Input
function* generator() {
console.log("Sent", function.sent);
console.log("Yield", yield);
}
const iterator = generator();
iterator.next(1); // Logs "Sent 1"
iterator.next(2); // Logs "Yield 2"
Output
let generator = _skipFirstGeneratorNext(function* () {
const _functionSent = yield;
console.log("Sent", _functionSent);
console.log("Yield", yield);
});
Stage 2: export-ns-fromβ
babel-plugin-transform-export-namespace
: a shorthand to import/reexport a namespace. Split out from the oldtransform-export-extensions
which combined this proposal with another
Input
export * as ns from "mod";
Output
import * as ns from "mod";
export {ns};
Stage 1: export-default-fromβ
babel-plugin-transform-export-default
: a shorthand to import/reexport something. Split out from the oldtransform-export-extensions
which combined this proposal with another
Input
export v from "mod";
Output
import _v from "module";
export { _v as v };
Stage 1: Optional Chaining (new)β
babel-plugin-transform-optional-chaining
: the operator (?.
) allows you to handle properties of deeply nested objects without worrying about undefined intermediate objects.
Input
a?.b = 42;
Output
var _a;
(_a = a) == null ? void 0 : _a.b = 42;
ES2015: new.target
β
babel-plugin-transform-new-target
: we never got around to implementingnew.target
support earlier, so now there is a plugin for it that will be included in the ES2015/env presets.
Example
// with a function
function Foo() {
console.log(new.target);
}
Foo(); // => undefined
new Foo(); // => Foo
// with classes
class Foo {
constructor() {
console.log(new.target);
}
}
class Bar extends Foo {
}
new Foo(); // => Foo
new Bar(); // => Bar
Input
class Foo {
constructor() {
new.target;
}
test() {
new.target;
}
}
Output
class Foo {
constructor() {
this.constructor;
}
test() {
void 0;
}
}
π New Featureβ
.babelrc.js
β
*.js
configuration files are fairly common in the JavaScript ecosystem. ESLint and Webpack both allow for .eslintrc.js
and webpack.config.js
configuration files, respectively.
Writing configuration files in JavaScript allows for dynamic configuration, making it possible to write a single configuration file that can adapt to different environments programmatically.
var env = process.env.BABEL_ENV || process.env.NODE_ENV;
var plugins = [];
if (env === 'production') {
plugins.push.apply(plugins, ["a-super-cool-babel-plugin"]);
}
module.exports = { plugins };
var env = process.env.BABEL_ENV || process.env.NODE_ENV;
module.exports = {
plugins: [
env === 'production' && "another-super-cool-babel-plugin"
].filter(Boolean)
};
This was previously done through the env
configuration option, which is now deprecated. See below for more details.
TypeScriptβ
You can now use babel-preset-typescript
to allow Babel to strip types similar to how babel-preset-flow
works!
{
"presets": ["typescript"]
}
We're working on a guide for how to setup TypeScript and Babel with the TypeScript team, which should be finished before the official 7.0 release. TL;DR is that you setup TS with --noEmit
or use it in the editor/watch mode so that you can use preset-env and other Babel plugins.
"Pure" Annotation in specific transforms for minifiersβ
After #6209, ES6 classes that are transpiled will have a /*#__PURE__*/
comment that minifiers like Uglify and babel-minify can use for dead code elimination. These annotations may expand to our helper functions as well.
Input
class C {
m(x) {
return 'a';
}
}
Output
var C = /*#__PURE__*/ function () {
function C() {
_classCallCheck(this, C)
}
C.prototype.m = function m(x) {
return 'a';
};
return C;
}();
π Other Breaking Changesβ
Removed babel-preset-flow
from babel-preset-react
β
This was important because we got a lot of complaints from users that weren't using any types/flow that they ended up writing invalid JS but there was no syntax error because they used the react preset.
Also we have the TypeScript preset now, so it didn't make sense to include flow
in the react preset itself anymore.
Integrationsβ
Packages like grunt-babel
, gulp-babel
, rollup-plugin-babel
, etc all used to have babel-core
as a dependency.
After v7, we plan to move babel-core
to be a peerDependency like babel-loader
has. This lets all these packages not have to bump major versions when the babel-core
API hasn't changed. Thus they are already published as 7.0.0
since we don't expect any further changes to those packages.