Did you know that Babel inadvertently fixes some errors? Me neither. In one of my projects, I switched from
babel-preset-env without expecting any problems.
But this is what happened. Since I don’t care about legacy browsers, it immediately switched off all plugins and introduced two bugs in the codebase.
After some investigation, it turned out that some transpilations “fix” some edge cases. And in turn, switching them off surfaced the errors.
When you use block-scoped values, like a
const, Babel rewrites them to traditional
vars. It takes care of block-scoping, so most of the times they behave as they should.
But it does not handle a specific scenario. For this input code (Try it):
Babel outputs this:
It’s almost identical; only the
const has been rewritten to
var. But if you run it, the babelified code sets
undefined, while the original one throws an Error.
The difference between
var – apart from the scoping – is how they are hoisted. The
var declaration is moved to the top of the scope and set
c is accessible inside the function call.
On the other hand,
const is moved to the top but left uninitialized. Inside the function call,
c is still uninitialized, it is in the so-called temporal dead zone, so accessing it throws an Error.
JS Tips newsletter
Subscribe now and get it
Convert Array-like to iterable
The other edge case is how iterables are handled.
Consider the following code (Try it):
o is a so-called Array-like structure. It has a
length property, and the numerical keys return the appropriate elements. In this case, it is an empty array (length: 0).
Running this code results in an error:
The array destructuring operator works only on iterables. Array-likes are supported by some built-in functions, but they are not enough in this case.
Since iterables are required to have a
[Symbol.iterator] function and
o clearly does not have it, the error is expected.
Babel produces the following code for the above input:
The key part is the
_toConsumableArray function. It makes a full-fledged Array out of its parameter. Since
false, it returns
Array.from(o). That function accepts an Array-like and returns an Array. Since then, it behaves exactly like
. Therefore, the code returns an empty Array, instead of throwing an Error.
There might be other edge cases that get “fixed” by transpilation, and cases like these might surface errors in an update.
This might cause problems bumping even minor versions. For example,
babel-preset-env supports time-dependent queries, like last x versions. With a new browser version, a plugin might get disabled, surfacing an error.
Fortunately, these errors are rare, and they are both known issues. But don’t expect them to just go away. They are hard to implement right, and therefore, it’s more likely you’ll update sooner than the fix is released.
By knowing errors like these exist, give attention to plugins that get enabled/disabled during an update.