Skip to main content

6.23.0 Released

ยท 7 min read

In this release: multiple improvements to the react-constant-elements plugin by @STRML, some codegen optimizations, and lots of bug fixes! Thanks to @loganfsmyth for the release + reviews!

Shoutouts to @xtina-starr, @finkef, @chitchu, @yongxu, @jwbay, @hex13 for their first PRs! ๐ŸŽ‰

Check out GitHub for the whole changelog.


I'll be writing up the 7.0 post (our current progress) soon so look out for that! We want to do whatever we can to make it easy for both end-users and plugin/tool authors to upgrade seamlessly: whether it be a beta period for the release, a 7.0 upgrade guide, codemods if necessary, a bot to automatically upgrade your OSS project from 6 to 7, or any other suggestions you can give us!

Since not everyone realises, I wanted to re-iterate again that our team is still a small group of volunteers. There's no company sponsor or even anyone working on it full time.

We'd love for you to contribute (especially not code!), so please reach out to us! More designers, technical writers/editors, and teachers for our website would be amazing.

And in other news, Babel has been accepted as a Rails Girls Summer of Code project as well as waiting to hear back as a mentor organization for Google Summer of Code!


๐Ÿš€ New Featureโ€‹

#5236 transform-es2015-block-scoping: Add option throwIfClosureRequired to throw on slow code. (@spicyj)โ€‹

babel.config.json
{
"plugins": [
["transform-es2015-block-scoping", {
"throwIfClosureRequired": true
}]
]
}

In cases such as the following, it is impossible to rewrite let/const without adding an additional function and closure while transforming:

JavaScript
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 1);
}

In extremely performance-sensitive code, this can be undesirable. If "throwIfClosureRequired": true is set, Babel throws when transforming these patterns instead of automatically adding an additional function.

#4812 transform-react-constant-elements: Support pure expressions (@STRML)โ€‹

Adds a path.isPure() check to the plugin.

The expression will remain in the hoisted code, even though it could be statically evaluated. UglifyJS/Babili will take care of that in many cases.

In

JavaScript
const OFFSET = 3;

var Foo = React.createClass({
render: function () {
return (
<div tabIndex={OFFSET + 1} />
);
}
});

Out

JavaScript
const OFFSET = 3;

var _ref = <div tabIndex={OFFSET + 1} />;

var Foo = React.createClass({
render: function () {
return _ref;
}
});

Deopt

As noted in facebook/react#3226, it's not safe to reuse elements with mutable props.

JavaScript
<div style={
{ width: 100 }
} />

#5288 babel-preset-flow: Add new preset (@thejameskyle)โ€‹

babel-preset-flow just includes transform-flow-strip-types.

Before (still valid)

babel.config.json
{
"plugins": ["transform-flow-strip-types"]
}

After

babel.config.json
{
"presets": ["flow"]
}

FYI: the React preset still includes the flow plugin by default (we might change it when TS support is added)

Thanks to @simnalamburt for giving us the package name!

#5230 babel-traverse: Add extra sibling methods (@chitchu)โ€‹

For plugin authors: there's already a path.getSibling(number), so we're adding a few helper methods.

JavaScript
path.getPrevSibling(); // path.getSibling(path.parentPath.key - 1)
path.getNextSibling(); // path.getSibling(path.parentPath.key + 1)
path.getAllPrevSiblings(); // returns Array<NodePath> of previous siblings
path.getAllNextSiblings();// returns Array<NodePath> of next siblings

๐Ÿ› Bug Fixesโ€‹

Because almost every bug fix can be an opportunity to learn more about JavaScript and how the tool that you use works, I would check out some of the PRs!

#5298 Fix loose transform-es2015-for-of with label. (@jridgewell)โ€‹

JavaScript
b: for (let c of d()) { // previously, the label was completely dropped
for (let e of f()) {
continue b;
}
}

#5153 transform-react-constant-elements: Hoisting fixes (@STRML)โ€‹

Better hoisting inside variable declarations

Input

JavaScript
function render() {
const bar = "bar", renderFoo = () => <foo bar={bar} baz={baz} />, baz = "baz";

return renderFoo();
}

Output

JavaScript
function render() {
const bar = "bar",
renderFoo = () => _ref2,
baz = "baz",
_ref2 = <foo bar={bar} baz={baz} />;

return renderFoo();
}

Hoisting with Higher Order Components

Input

JavaScript
const HOC = component => component;

const Parent = () => (
<div className="parent">
<Child/>
</div>
);

export default Parent;

let Child = () => (
<div className="child">
ChildTextContent
</div>
);
Child = HOC(Child);

Output

JavaScript
const HOC = component => component;

const Parent = () => _ref;

export default Parent;

var _ref2 = <div className="child">
ChildTextContent
</div>;

let Child = () => _ref2;
Child = HOC(Child);

var _ref = <div className="parent">
<Child />
</div>;

#5143 transform-react-constant-elements: Fix PathHoister hoisting JSX member expressions on this (@STRML)โ€‹

<this.component /> was previously hoisted outside its own function (doesn't make sense because otherwise this would be undefined)

JavaScript
function render() {
this.component = "div";
return () => <this.component />;
}
JavaScript
function render() {
this.component = "div";

var _ref = <this.component />;

return () => _ref;
}

#5030 transform-do-expressions: Prevent multiple return statements in a loop when replacing expressions. (@existentialism)โ€‹

JavaScript
let p
let a = do {
while (p = p.parentPath) {
if (a) {
'a'
} else {
'b'
}
}
};
JavaScript
let p;
let a = function () {
var _ret;

while (p = p.parentPath) {
if (a) {
_ret = 'a';
} else {
_ret = 'b';
}
}
return _ret; // previously had an extra return
}();

#5260 babel-register: Fix a TypeError with the cache. (@xtuc)โ€‹

#5206 babel-traverse: Deopt evaluation of undefined with a local binding (@boopathi)โ€‹

If undefined, NaN, Infinity are redefined, deopt.

#5195 babel-plugin-transform-runtime: Don't compile certain symbol properties. (@taion)โ€‹

Don't pull in the individual Symbol.asyncIterator/Symbol.observable polyfills and pull in the full Symbol polyfill instead.

#5258 babel: Check if it is installed globally and displays correct cli message. (@xtina-starr)โ€‹

Now if you install babel the error message will display either -g or not.

#5270 babel-generator: Emit parens for await of ternary expressions. (@erikdesjardins)โ€‹

JavaScript
async function asdf() {
await (1 ? 2 : 3);
}

#5193 babel-generator: Fix missing parens when FunctionExpression is a tag in a template string. (@existentialism)โ€‹

JavaScript
(() => {})``;
(function(){}``);

#5235 transform-es2015-modules-commonjs: Limit export node default assignment stack size #4323. (@mattste)โ€‹

An interesting issue when importing/exporting a lot!

JavaScript
import { foo, foo1, foo2 ... } from "foo"; // assume ... is 100 imports/exports
export { foo, foo1, foo2 ... }

Part of the generated code looks like:

JavaScript
exports.Foo6 = exports.Foo5 = ...

Thus with a file that exports a lot of modules it creates so many nested assignment nodes in the AST the code generator errors with Maximum call stack size exceeded.

The solution is to break up the expression into sets of 100.

Output

JavaScript
exports.foo100 = undefined; // split by 100
exports.foo99 = exports.foo98 = ... exports.foo1 = exports.foo = undefined

#5255 babel-generator: Use trim instead of lodash/trimEnd for codegen performance (@jwbay)โ€‹

lodash/trimEnd executes a regex against potentially massive strings which can freeze node. (106ms vs. 5ms)

#5050 babel-traverse: Rewrite Hub as an interface (@yongxu)โ€‹

This was reverted due to an incompatible change to babel-core

There are a few cases where babel-traverse can't be used standalone so this removes some code that tied babel-traverse to babel-core's implementation.


๐ŸŒ Committers: 20โ€‹

Check out Github for the whole changelog!