You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
var declarations inside if blocks not hoisted when using __esm wrappers #4348
Full disclosure: this issue was identified and minimum repro was isolated by Claude Code.
It's a real issue we ran into building Quarto, triggered by upstream dependencies jszip and @jspm/core.
When esbuild creates __esm lazy initialization wrappers (triggered by CommonJS requiring ESM), it fails to hoist var declarations from inline if statement blocks to module scope.
Source pattern
if(condition)varb=getValue();
Current output (buggy)
functionuseB(){returnb();// ReferenceError: b is not defined}varinit_module=__esm({"module.js"(){if(condition)varb=getValue();// b scoped to init function}});
Expected output
varb;// Hoisted to module scopefunctionuseB(){returnb();// OK}varinit_module=__esm({"module.js"(){if(condition)b=getValue();// Assignment only}});
It is not possible to reproduce this bug in the playground since the bug requires:
Multi-file setup (CommonJS requiring ESM)
Actual bundling that triggers __esm wrappers
The specific module format interaction
The repository contains two reproductions:
1. flat/ - Plain esbuild (simpler)
Uses pre-downloaded JSPM CDN files with plain esbuild.
cd flat/
npm install
npx esbuild entry-cjs-real-jspm.js --bundle --outfile=bundle-cjs-real-jspm.js
npx eslint bundle-cjs-real-jspm.js # Shows 16 errors
node bundle-cjs-real-jspm.js # ReferenceError: b is not defined
2. bundled/ - With esbuild-deno-loader (matches real-world usage)
Uses @luca/esbuild-deno-loader plugin with mixed CommonJS/ESM setup.
cd bundled/
npm install
deno run -A bundle-with-deno-loader.ts
npx eslint bundle-hybrid.js # Shows 18 errors
Impact
This affects:
Projects with mixed CommonJS/ESM modules
Libraries using minified inline var declarations (e.g., @jspm/core via JSPM CDN)
Any code where esbuild generates __esm wrappers
The bug is often masked by defensive programming. In our environment it does not cause an actual problem at runtime, but it causes eslint to fail, requiring globals to be declared.
Related
This appears related to the fix in esbuild 0.12.17 (PR #1455) for var hoisting in for loop initializers, but if blocks weren't covered.
Note for myself: This is happening because esbuild doesn't introduce a scope in this case, since there isn't a block. The lack of a scope is not otherwise a problem since let and const aren't allowed in this position. But the code to hoist var exits early if it thinks it's a top-level statement, which it checks by checking whether the current scope is the module scope.
Activity
evanw commentedon Dec 1, 2025
Thanks for the report. I can reproduce the problem. Here's a live repro: link
evanw commentedon Dec 3, 2025
Note for myself: This is happening because esbuild doesn't introduce a scope in this case, since there isn't a block. The lack of a scope is not otherwise a problem since
letandconstaren't allowed in this position. But the code to hoistvarexits early if it thinks it's a top-level statement, which it checks by checking whether the current scope is the module scope.fix evanw#4348: bundler bug with `var` inside `if`
use latest esbuild for quarto bundle
Update dependency esbuild to v0.28.2 (#2)