6.23.0 Released

Posted Feb 13, 2017 by Henry Zhu

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鈥檒l 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鈥檚 no company sponsor or even anyone working on it full time.

We鈥檇 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)

{
  "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:

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

const OFFSET = 3;

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

Out

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鈥檚 not safe to reuse elements with mutable props.

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

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

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

Before (still valid)

{
  "plugins": ["transform-flow-strip-types"]
}

After

{
  "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鈥檚 already a path.getSibling(number), so we鈥檙e adding a few helper methods.

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 alsmot 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)

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

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

  return renderFoo();
}

Output

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

  return renderFoo();
}

Hoisting with Higher Order Components

Input

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

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鈥檛 make sense because otherwise this would be undefined)

function render() {
  this.component = "div";
  return () => <this.component />;
}
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)

let p
let a = do {
  while (p = p.parentPath) {
    if (a) {
      'a'
    } else {
      'b'
    }
  }
};
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鈥檛 compile certain symbol properties. (@taion)

Don鈥檛 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)

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

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

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

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

An interesting issue when importing/exporting a lot!

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

Part of the generated code looks like:

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

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鈥檛 be used standalone so this removes some code that tied babel-traverse to babel-core鈥檚 implementation.


馃審 Committers: 20

Check out Github for the whole changelog!