August 26, 2015
Though Babel is a transpiler to convert ESNext code to ES5, it can be used to optimize the code as well.
Let's say we want to convert following ES6 code using Babel.
let a = 10;
let b = 42;
if (a < b) {
console.log("a is less than b");
} else {
console.log("b is less than a");
}
It will get translated to:
"use strict";
var a = 10;
var b = 42;
if (a < b) {
console.log("a is less than b");
} else {
console.log("b is less than a");
}
All good so far. Let's try Babel's constant folding plugin (Link is not available). I am compiling the ES6 code from command line this time.
babel --plugins constant-folding index.js --out-file bundle.js -w
This gives us following output:
"use strict";
var a = 10;
var b = 42;
if (true) {
console.log("a is less than b");
} else {
console.log("b is less than a");
}
If condition changed from (a < b)
to (true)
.
The constant-folding
plugin has smartly evaluated the conditional expression a < b
and
replaced the code with the result of that expression.
This plugin can also optimize other expressions as shown below.
// Unary operators
console.log(!true);
// Binary expression
console.log(20 + 22);
// Function calls
console.log(Math.min(91, 2 + 20));
Which gets optimized to:
// Unary operators
console.log(false);
// Binary expression
console.log(42);
// Function calls
console.log(22);
Though we are using a "constant folding plugin" to achieve this optimization, the real work happens in Babel itself.
For every expression in the code, the constant folding plugin calls evaluate
function from Babel source code.
This function checks whether it can confidently find end value for a given expression.
The evaluate
function returns confidence level and end value for any given expression. Based on this "confidence level", constant folding plugin replaces the expression with their end values altering our original code as follows.
For code Math.min(10, 20)
, evaluate will return
{ confident: true, value: 10 }
For code a < b
, evaluate will return
{ confident: true, value: true }
.
But for user defined function like foo('bar')
or browser defined console.log('hello')
, evaluate will return
{ confident: false, value: undefined }
.
In the above case "confident" value will be "false" even if function returns a constant value. For example
for code foo(100)
, evaluate will return
{ confident: false, value: undefined }
.
In the above case function foo
will always return 100
. Still Babel has low confidence level. Why? That's because
Babel sees that it is a function and it bails out. It does not even look inside to try to figure things out.
Here is evaluate code in Babel. You should check it out.
How much help we will get from Babel for optimizing our code? Will it optimize everything?
The answer is unfortunately no.
As of now, Babel optimizes logical, binary, conditional expressions. It can also evaluate function calls on literals like "babel".length
confidently if the literal is string or number.
For function calls, it supports only certain callees like String
, Number
and Math
. So call to a user defined function, even if it's returning a fixed value, will not be optimized.
This feature looks great. But it's available as experimental feature.
If you use the plugin you will get
following warning. unless you enable experimental
flag.
$ babel --plugins constant-folding index.js --out-file bundle.js -w
[BABEL] index.js: THE TRANSFORMER constant-folding HAS BEEN MARKED AS EXPERIMENTAL AND IS WIP. USE AT YOUR OWN RISK. THIS WILL HIGHLY LIKELY BREAK YOUR CODE SO USE WITH **EXTREME** CAUTION. ENABLE THE `experimental` OPTION TO IGNORE THIS WARNING.
In order to get rid of warning you need to pass --experimental
flag
like this.
$ babel --plugins constant-folding index.js --out-file bundle.js -w
--experimental
In above code example, we know that the result of if (a < b)
is true
based on values of a and b.
Since the result is not going to change no matter what
there is no need
to have the if
and else
clauses.
That's dead code.
Can Babel help us eliminate dead code?
Yes with the help of minification.deadCodeElimination
option.
babel --optional minification.deadCodeElimination index.js --out-file bundle.js -w
Which converts earlier code to:
"use strict";
console.log("a is less than b");
I will talk about how Babel can eliminate dead code in a later post.
If this blog was helpful, check out our full blog archive.