Babel plugins: 'loose' mode caveats
December 18, 2019 • 3 min read • Tweet
Recently I was working on a JavaScript project that had babel
setup to
transpile ES6+
code into ES5
. For some functionality, I had to write a function
to get unique items in an array. The source code looks like this.
// Source code
const getUnique = (arr) => [...new Set(arr)];
Then I execute the function expecting it to work fine. but, it didn’t 😅
/**
* Expected output: [1,2]
* Actual output: [Set({1, 2})] 😮
*/
const uniqueArr = getUnique([1, 2, 1]);
I wasn’t sure what was happening. Why did it produce the wrong result? I double-checked the package versions, build tool config, restarted my build. But, the issue still persisted.
Finally, I decided to check the transpiled code.
// Transpiled code
var getUnique = function getUnique(arr) {
return [].concat(new Set(arr));
};
There it was! wrongly transpiled code. now I knew it was my babel config.
{
"presets": {
[
"@babel/preset-env",
{
"loose": true, "modules": false,
}
]
}
}
For some reason, loose
mode option was set to true
and was the real culprit 🙆♂️
What does loose
mode mean?
Many babel plugins have two modes:
- Normal mode: closely follows the ECMAScript 6 standard
- Loose mode: produces smaller & simple ES5 code, more like the handwritten one
Here is a example of generated code of loose
mode disabled(default) vs
loose
mode enabled.
loose
mode might generate potentially faster, smaller and old browser engine compatible ES5
code. but,
it might also introduce unintended results when switching from transpiled ES6+
to native ES6+
at
later stage as it produces code that is less faithful to ES6+
semantics.
As discussed in this GitHub issue
In loose mode, all iterables are assumed to be arrays.
So, when using loose
mode, some of the basic operations like converting a string
to an array using spread
operators might not work as expected.
// Input code
const charArr = [...'hello'];
/**
* Transpiled code in loose mode(Produces wrong result)
* Expected output: ["h", "e", "l", "l", "o"]
* Actual output: ["hello"]
*/
var charArr = [].concat('hello');
Should I use the loose
mode?
- Avoid it in large or shared projects unless you and everybody working on the project are okay with its limitations.
- If you are a library author, it should probably be okay to use it as you have full control over the source code.
Library authors publishing transpiled code:
— Jason Miller 🦊⚛ (@_developit) November 7, 2019
do you use loose mode?
↦ for Babel: ['@babel/env',{loose:true}]
↦ for TS: {downlevelIteration: false}
This was a fun issue I had to deal with recently. Hope you enjoyed reading this blog 😇 If you did, give me a follow @ganapativs 🙌
References:
Thanks: