One line in Babel config, env
preset’s loose
set to true
was causing a spread operator to disappear on only CommonJS builds (not ES Modules or UMD), which led to broken logic (program could not calculate opts.breakToTheLeftOf
correctly any more), program inserted extra blank lines. A crazy bug, isn’t it?
Situation
The html-crush
TypeScript source:
if (Array.isArray(opts.breakToTheLeftOf) && opts.breakToTheLeftOf.length) {
breakToTheLeftOfFirstLetters = [
...new Set(opts.breakToTheLeftOf.map((val) => val[0])),
].join("");
}
used to get transpiled into ESM (ES Modules, code with import
/export
):
if (Array.isArray(opts.breakToTheLeftOf) && opts.breakToTheLeftOf.length) {
breakToTheLeftOfFirstLetters = [
...new Set(opts.breakToTheLeftOf.map((val) => val[0])),
].join("");
}
but, CJS (CommonJS, code with require
) was transpiled into:
if (Array.isArray(opts.breakToTheLeftOf) && opts.breakToTheLeftOf.length) {
breakToTheLeftOfFirstLetters = []
.concat(
new Set(
opts.breakToTheLeftOf.map(function (val) {
return val[0];
})
)
)
.join("");
}
The ...
, ES6 spread operator disappears!!!
The Cause
It was just mis-configured Babel, loose: true,
line below:
// babel.config.js
const { NODE_ENV } = process.env;
module.exports = {
presets: [
"@babel/typescript",
[
"@babel/env",
{
targets: {
browsers: ["ie >= 11"],
},
exclude: ["transform-async-to-generator", "transform-regenerator"],
modules: false,
loose: true, // <----------- !!!
},
],
],
plugins: [
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-class-properties",
NODE_ENV === "test" && "@babel/transform-modules-commonjs",
].filter(Boolean),
};
Once loose
is disabled, all works fine again!
By the way, Babel documentation describes loose
very briefly:
Enable “loose” transformations for any plugins in this preset that allow them.
I didn’t expect this.
Learning
Especially for large, important open source packages, in unit tests, it’s wise to test all the builds: ESM, UMD and CJS. “If it quacks like a duck…” — there are no mysteries in programs, either tests pass, or they don’t. In theory, unit-testing all builds should safeguard against errors in the build configs. I set up every single unit test in html-crush
to check all three builds: UMD, CJS and ESM.
Conclusion
Thanks for Romain Vincent for raising the GitHub issue. And sorry to everybody who encountered it.