fix #4482: don't inline using declarations

This commit is contained in:
Evan Wallace
2026-06-11 10:39:53 -04:00
parent 7827020698
commit 040db75a5e
3 changed files with 21 additions and 1 deletions
+18
View File
@@ -2,6 +2,24 @@
## Unreleased
* Avoid inlining `using` and `await using` declarations ([#4482](https://github.com/evanw/esbuild/issues/4482))
Previously esbuild's minifier sometimes incorrectly inlined `using` and `await using` declarations into subsequent uses of that declaration, which then fails to dispose of the resource correctly. This bug happened because inlining was done for `let` and `const` declarations by avoiding doing it for `var` declarations, which no longer worked when more declaration types were added. Here's an example:
```js
// Original code
{
using x = new Resource()
x.activate()
}
// Old output (with --minify)
new Resource().activate();
// New output (with --minify)
{using e=new Resource;e.activate()}
```
* Fix module evaluation when an error is thrown ([#4461](https://github.com/evanw/esbuild/issues/4461), [#4467](https://github.com/evanw/esbuild/pull/4467))
If an error is thrown during module evaluation, esbuild previously didn't preserve the state of the module for subsequent module references. This was observable if `import()` or `require()` is used to import a module multiple times. The thrown error is supposed to be thrown by every call to `import()` or `require()`, not just the first. With this release, esbuild will now throw the same error every time you call `import()` or `require()` on a module that throws during its evaluation.
+1 -1
View File
@@ -9190,7 +9190,7 @@ func (p *parser) mangleStmts(stmts []js_ast.Stmt, kind stmtsKind) []js_ast.Stmt
// should have visited all the uses of "let" and "const" declarations
// by now since they are scoped to this block which we just finished
// visiting.
if prevS, ok := result[len(result)-1].Data.(*js_ast.SLocal); ok && prevS.Kind != js_ast.LocalVar {
if prevS, ok := result[len(result)-1].Data.(*js_ast.SLocal); ok && (prevS.Kind == js_ast.LocalLet || prevS.Kind == js_ast.LocalConst) {
last := prevS.Decls[len(prevS.Decls)-1]
// The binding must be an identifier that is only used once.
+2
View File
@@ -5265,6 +5265,8 @@ func TestMangleInlineLocals(t *testing.T) {
check("var x = 1; return x", "var x = 1;\nreturn x;")
check("let x = 1; return x", "return 1;")
check("const x = 1; return x", "return 1;")
check("using x = 1; return x", "using x = 1;\nreturn x;")
check("return async () => { await using x = 1; return x }", "return async () => {\n await using x = 1;\n return x;\n};")
check("let x = 1; if (false) x++; return x", "return 1;")
check("let x = 1; if (true) x++; return x", "let x = 1;\nreturn x++, x;")