Describe the bug
When a function has a parameter named undefined (the old UMD idiom (function (window, document, undefined) { ... })(window, document)) and the same file also refers to the global undefined, SWC renames the parameter to undefined1. The compressor then removes the parameter because it is never passed and rewrites most uses to void 0. It misses uses inside a hoisted function declaration that gets inlined into its call site -- those uses keep the name undefined1, which is no longer declared anywhere. In this case, we get a runtime error ReferenceError: undefined1 is not defined when that code runs.
This does not reproduce through swc.minify(), only through swc.transform() with jsc.minify. That is the call Parcel 2's @parcel/optimizer-swc makes.
To reproduce, the following is needed:
- A top-level reference to the global
undefined. Without it the output is correct.
- A parameter named
undefined.
- A function declaration that reads it and is inlined. The same body written as an inline function expression (
foo(function (x) { ... })) compiles correctly.
Both isModule: true and false reproduce the bug, as does mangle: false. compress: false does not reproduce the bug.
Input code
undefined;
(function (undefined) {
foo(bar);
function bar(x) {
return x === undefined;
}
})();
Config
{
"jsc": {
"target": "es2022",
"minify": {
"compress": true,
"mangle": true
}
},
"minify": true
}
Link to the code that reproduces this issue
https://play.swc.rs/?version=1.16.12&code=H4sIAAAAAAAAAyvNS0lNy8xLTbFW0EgrzUsuyczPU9AohYlqKlQrpOXnayQlFmlaK8AVALkaFSC5otSS0qI8hQoFW1tbhVKEWbUKtZoamtYAYW4Sq14AAAA%3D&config=H4sIAAAAAAAAA41VQY7bMAy87ysCn3vY5lAUfUBvfYOgWJSjVBYNkfImWOTvpRU7m93QRi9BzNGQIjmk3l92u%2BZEbfNr9y5%2F5WOwmSDfv8VCl8T2LJYG2t5Sm8PAzbcFPdEEeRsJqul6Qxq2uQOuLNq%2F7vczo4mIBAtjtvUhBX95jNliP2QgerCJVVyWHhLTZ%2F6MZXybAM7l0X5AjGDTBmIsmZAYOsia4xZjtAOBGW1WvEw3tTkQaiEmsDA4M2QcVDy5wAGTxHxGHVhnWnSgQCFDy2EEjSaxhJZI0lPyqbCDQ%2Bm62ucvbBhtLJaVmHCuLZHbKl6PGIiNL0kr4Q1cqcENnIv7lRm8ycAlp2feCUNa6clfAKlAtETJ9qD5rSe86GmN7TeZIXmRLF8UXPStZZmgk6KaELxS2akykDlo3czgSgtTZVvtOjO8Uj4KDgx4L1pRXNNb4PaoBeXLAOgVQPprvaaqG2DuU7iCTwOxAf%2BWLFkX2Hyit3xcR%2BnSHzBuBOiBj%2Bg2DkgrGNfhLFviPKzjJTkQaYBTjxSqwPMSkAFgNLHuyydtyHiIR9NFPHysifnA9b6He5u6Ou8P%2B5JxiDBCXJPxf4zIJip3GydVL5P9NL3wUxOllcEL318%2FPRuSysvyW5NqenTlIaGqydtz8qP5OLS8HEvVmkB%2FFmKt0%2FUfj5GfKOMGAAA%3D
SWC Info output
Operating System:
Platform: win32
Arch: x64
Machine Type: x86_64
Version: Windows 11 Pro
CPU: (14 cores)
Models: Intel(R) Core(TM) Ultra 7 165U
Binaries:
Node: 22.23.2
npm: N/A
Yarn: N/A
pnpm: N/A
Relevant Packages:
@swc/core: 1.16.12
@swc/helpers: 0.5.23
@swc/types: 0.1.28
SWC Config:
output: N/A
.swcrc path: N/A
Next.js info:
output: N/A
Expected behavior
The shadowed undefined is either kept declared or replaced with void 0 everywhere:
foo(function(o){return void 0===o});
That is what swc.minify() produces for the same input with { compress: true, mangle: true } (checked on 1.16.2).
Actual behavior
foo(function(n){return n===undefined1});
undefined1 is never declared, so calling the callback throws ReferenceError: undefined1 is not defined.
Version
1.16.12
Additional context
Found in a Parcel 2 production build (minified by @parcel/optimizer-swc), where Hammer.js 2.0.8 is pulled in by chartjs-plugin-zoom 2.2.0. Hammer's UMD wrapper is (function(window, document, exportName, undefined) { ... })(window, document, 'Hammer'), and another module in the same bundle uses the global undefined (interaction: { axis: undefined } in chartjs-plugin-annotation). The minified bundle ends up with:
if(8!=t.eventType&&(l>25||i.velocity===undefined1))
from hammer.js line 610:
if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
The reproduction script:
const swc = require("@swc/core")
const src = `
undefined;
(function (undefined) {
foo(bar);
function bar(x) {
return x === undefined;
}
})();
`
swc
.transform(src, {
jsc: { target: "es2022", minify: { compress: true, mangle: true } },
minify: true,
configFile: false,
swcrc: false,
})
.then(({ code }) => console.log(code))
// foo(function(n){return n===undefined1});
Related issues:
Describe the bug
When a function has a parameter named
undefined(the old UMD idiom(function (window, document, undefined) { ... })(window, document)) and the same file also refers to the globalundefined, SWC renames the parameter toundefined1. The compressor then removes the parameter because it is never passed and rewrites most uses tovoid 0. It misses uses inside a hoisted function declaration that gets inlined into its call site -- those uses keep the nameundefined1, which is no longer declared anywhere. In this case, we get a runtime errorReferenceError: undefined1 is not definedwhen that code runs.This does not reproduce through
swc.minify(), only throughswc.transform()withjsc.minify. That is the call Parcel 2's@parcel/optimizer-swcmakes.To reproduce, the following is needed:
undefined. Without it the output is correct.undefined.foo(function (x) { ... })) compiles correctly.Both
isModule: trueandfalsereproduce the bug, as doesmangle: false.compress: falsedoes not reproduce the bug.Input code
Config
{ "jsc": { "target": "es2022", "minify": { "compress": true, "mangle": true } }, "minify": true }Link to the code that reproduces this issue
https://play.swc.rs/?version=1.16.12&code=H4sIAAAAAAAAAyvNS0lNy8xLTbFW0EgrzUsuyczPU9AohYlqKlQrpOXnayQlFmlaK8AVALkaFSC5otSS0qI8hQoFW1tbhVKEWbUKtZoamtYAYW4Sq14AAAA%3D&config=H4sIAAAAAAAAA41VQY7bMAy87ysCn3vY5lAUfUBvfYOgWJSjVBYNkfImWOTvpRU7m93QRi9BzNGQIjmk3l92u%2BZEbfNr9y5%2F5WOwmSDfv8VCl8T2LJYG2t5Sm8PAzbcFPdEEeRsJqul6Qxq2uQOuLNq%2F7vczo4mIBAtjtvUhBX95jNliP2QgerCJVVyWHhLTZ%2F6MZXybAM7l0X5AjGDTBmIsmZAYOsia4xZjtAOBGW1WvEw3tTkQaiEmsDA4M2QcVDy5wAGTxHxGHVhnWnSgQCFDy2EEjSaxhJZI0lPyqbCDQ%2Bm62ucvbBhtLJaVmHCuLZHbKl6PGIiNL0kr4Q1cqcENnIv7lRm8ycAlp2feCUNa6clfAKlAtETJ9qD5rSe86GmN7TeZIXmRLF8UXPStZZmgk6KaELxS2akykDlo3czgSgtTZVvtOjO8Uj4KDgx4L1pRXNNb4PaoBeXLAOgVQPprvaaqG2DuU7iCTwOxAf%2BWLFkX2Hyit3xcR%2BnSHzBuBOiBj%2Bg2DkgrGNfhLFviPKzjJTkQaYBTjxSqwPMSkAFgNLHuyydtyHiIR9NFPHysifnA9b6He5u6Ou8P%2B5JxiDBCXJPxf4zIJip3GydVL5P9NL3wUxOllcEL318%2FPRuSysvyW5NqenTlIaGqydtz8qP5OLS8HEvVmkB%2FFmKt0%2FUfj5GfKOMGAAA%3D
SWC Info output
Expected behavior
The shadowed
undefinedis either kept declared or replaced withvoid 0everywhere:That is what
swc.minify()produces for the same input with{ compress: true, mangle: true }(checked on 1.16.2).Actual behavior
undefined1is never declared, so calling the callback throwsReferenceError: undefined1 is not defined.Version
1.16.12
Additional context
Found in a Parcel 2 production build (minified by
@parcel/optimizer-swc), where Hammer.js 2.0.8 is pulled in bychartjs-plugin-zoom2.2.0. Hammer's UMD wrapper is(function(window, document, exportName, undefined) { ... })(window, document, 'Hammer'), and another module in the same bundle uses the globalundefined(interaction: { axis: undefined }inchartjs-plugin-annotation). The minified bundle ends up with:from
hammer.jsline 610:The reproduction script:
Related issues:
ReferenceError: undefined1 is not defined, also triggered by a top-levelundefined;. It was fixed in v1.1.15 by changing how hygiene handles special identifiers, so this may be a regression or a path that fix didn't cover.undefined,NaN, andInfinityident in decl is rewritten #8336 (open) is another case of a local binding namedundefinedbeing renamed toundefined1inconsistently, without minification.globalThisident in decl is rewritten #8317 was the same problem forglobalThis, fixed in the renamer (fix(es/renamer): AllowglobalThisto be shadowed #8327).