-
Notifications
You must be signed in to change notification settings - Fork 0
Home
This fork of babel generates a more optimal output for today's browsers and is specialised for the µ micro-framework.
Default Parameters
Given a function with default parameters like:
function foo(a=2, b=3) {
return a + b;
}The upstream version generates output which uses the expensive arguments object:
function foo() {
var a = arguments[0] === undefined ? 2 : arguments[0];
var b = arguments[1] === undefined ? 3 : arguments[1];
return a + b;
}Whilst this is in line with the ES6 spec, the value it provides by making foo.length consistent is not something that's commonly used. Instead, we generate this more performant output:
function foo(a, b) {
a === undefined && (a = 2);
b === undefined && (b = 3);
return a + b;
}Export Declarations
When defining exports, e.g.
export function foo() {
alert("hi");
}The upstream version generates the equivalent of:
function foo() {
alert("hi");
}
exports.foo = foo;
Object.defineProperty(exports, "__esModule", {
value: true
});Whilst defining __esModule helps with compatibility with various loaders, we don't use it within µ, so we instead just output:
function foo() {
alert("hi");
}
exports.foo = foo;Import Declarations
Similarly, when defining imports, e.g.
import foo from "foo";Upstream will generate:
var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; };
var foo = _interopRequire(require("foo"));We instead generate the following without the __esModule check:
var foo = require("foo")["default"];Note: This only works for the default module type of common. If you specify an alternative type, e.g. babel --modules amd, then it will behave as it would in upstream.
For...Of Loops
Upstream currently transforms:
for (var user of users) {
display(user.name);
}Into:
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = users[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var user = _step.value;
display(user.name);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"]) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}Not only does this mean we can't use for...of loops on Arrays in older browsers without hacking Array.prototype, but it also puts a loop inside a try/catch which tends to be deadly for performance.
We instead generate the following:
for (var user, _isArray = Array.isArray(users), _i = 0, _j, _iterator = !_isArray && users[Symbol.iterator]();;) {
if (_isArray) {
if (_i >= users.length) break;
user = users[_i++];
} else {
_j = _iterator.next();
if (_j.done) break;
user = _j.value;
}
display(user.name);
}This fast-paths Array values in for...of loops like in --loose mode, drops support for calling any generator return values, and tries to minimise unnecessary assignments during variable declarations.
For...In Loops
In a complete break with standards, we desugar for...in loops to loop over Array values. That is, we transform loops like:
for (var user in users) {
display(user.name);
}Into:
for (var _i = 0; _i < users.length; _i++) {
var user = users[_i];
display(user.name);
}The reasoning for this is that standard for...in loops were primarily used to find all the enumerable properties found directly on an object. Not only is Object.keys() a significantly faster way of finding that out, but it's also a lot shorter. Compare:
var props = Object.keys(obj);Versus:
var hasProp = {}.hasOwnProperty,
props = [];
for (var prop in obj) {
if (!hasProp.call(obj, prop))
continue;
props.push(prop);
}And since all the browsers we care about support Object.keys(), it made sense to take advantage of for...in loops as a way to loop over Arrays without having to constantly check if it's an Array on every iteration, like we do with for...of loops.
Array Comprehensions
Thanks to the non-standard, for...in loops, we can now do much faster comprehensions over Array values. For example, the following:
var cities = [for (user in users) if (user.isActive()) user.city];Gets transpiled into:
var cities = (function () {
var _cities = [];
for (var _i = 0; _i < users.length; _i++) {
var user = users[_i];
if (user.isActive()) {
_cities.push(user.city);
}
}
return _cities;
})();Note: var declarations automatically get injected into both for...in and for...of array and generator comprehensions, but not in loops.
JSX
Like React, we support the JSX syntax, e.g.
var Item = mu.View({
render() {
return <div class="item">{this.text}</div>;
}
});Gets translated into:
var Item = mu.View({
_name: "Item",
render: function render() {
return mu.Tag("div", {className: "item"}, this.text);
}
});Minor differences to React are:
- The
_nameproperty gets auto-assigned in place of the longerdisplayName. - String elements like
"div"are instantiated usingmu.Tag. - Non-string elements like
Itemare instantiated usingmu.Elem. - Any use of literal
classattributes in JSX get translated toclassNameautomatically.