Repository navigation
Fix 14585 — unminified identifier collisions - #17930
Merged
Merged
Conversation
Identifier collision from block scope var when not minifying identifiers
…This allows bundle_v2's renameSymbolsInChunk function to tell its renamer about hoisted block-scope var declarations so its child scopes do not create collisions
jbarrieault
force-pushed
the
jb/issue-14585
branch
from
March 6, 2025 04:47
0a2713e to
9ceb0f7
Compare
jbarrieault
commented
Mar 6, 2025
| .binding = p.b(B.Identifier{ .ref = ref }, local.loc), | ||
| }; | ||
| try partStmts.append(p.s(S.Local{ .decls = G.Decl.List.init(decls) }, local.loc)); | ||
| try p.declared_symbols.append(p.allocator, .{ .ref = ref, .is_top_level = true }); |
Contributor
Author
paperclover
suggested changes
Mar 6, 2025
paperclover
left a comment
Contributor
There was a problem hiding this comment.
This is not the correct fix. It is a workaround, and actually the same bug and workaround I ran into somewhere else.
// TODO(paperclover): fix the renamer bug. this bug
// theoretically affects all usages of temp refs, but i cannot
// find another example of it breaking (like with `using`)
p.declared_symbols.append(p.allocator, .{
.is_top_level = true,
.ref = ctx_storage.*.?.signature_cb,
}) catch bun.outOfMemory();It may be worthwhile to compare esbuild's code around this point. Note how it does not append to declared_symbols in their code.
If this PR is blocking something important, i'm ok with adding a TODO comment here. but the real bug is in renaming, hoisting, or symbol merging code. I haven't investigated enough to know.
paperclover
reviewed
Mar 6, 2025
| }, | ||
| }); | ||
| // https://github.com/oven-sh/bun/issues/14585 | ||
| itBundled("identifiers/SameNameDifferentModulesWithMinifyIdentifiersDisabled", { |
Contributor
There was a problem hiding this comment.
by the way this is a good and correct test
This was referenced Apr 1, 2026
BYK
added a commit
to getsentry/cli
that referenced
this pull request
Apr 1, 2026
… bug (#619) ## Summary - Replace `Bun.build()` with esbuild in the binary build's Step 1 (TS → JS bundling) - Restores full identifier minification that was disabled in #617 - Fixes sourcemap quality: esbuild produces 27,860 names vs Bun's empty array ## Problem Bun's identifier minification has an unfixed collision bug ([oven-sh/bun#14585](oven-sh/bun#14585)) where minified output produces name collisions across module scopes, causing runtime `X is not a function` errors. PR #617 worked around this by disabling identifier minification (`identifiers: false`), but that loses ~22% bundle size reduction and still uses Bun's sourcemaps which have an empty `names` array. The upstream fix ([oven-sh/bun#17930](oven-sh/bun#17930)) was acknowledged as a workaround — the real bug in Bun's renamer/hoisting code was never properly fixed. We still hit collisions on Bun 1.3.11. ## Solution Use esbuild (already a devDependency for the npm bundle) for the binary build's bundling step. The compile step still uses `Bun.build({ compile: true })` since that's the only way to produce native Bun binaries. esbuild's output is standard ESM that `Bun.build({ compile })` accepts without issues. Config: `platform: "node"`, `target: "esnext"`, `format: "esm"`, `external: ["bun:*"]`, `sourcemap: "external"`, `minify: true` ## Size comparison | Metric | PR #617 (identifiers:false) | This PR (esbuild full minify) | |--------|---------------------------|-------------------------------| | JS bundle | 3.64 MB | 2.82 MB (**-22%**) | | Binary (gzip) | ~28.4 MB | ~28.4 MB | | Sourcemap names | 0 (empty!) | 27,860 | | Sourcemap sources | N/A | 1,006 | ## Verification - `auth status` (PR #617 crash scenario): renders markdown correctly - E2E tests: 122 pass, 0 fail, 3 skip - Debug ID injection: works (UUID generated) - `Bun.build({ compile })` accepts esbuild ESM output - Lint: clean ## Changes Single file: `script/build.ts` - Added esbuild import, replaced `Bun.build()` in `bundleJs()` with `esbuild()` - Added `mkdirSync("dist-bin")` since esbuild doesn't auto-create output dirs - Updated JSDoc Made with [OpenCode](https://opencode.ai)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes #14585
This fixes a bundling bug in which the parsing step fails to hoist block-scoped vars, which can result in identifier collisions.
Implementation
I did a fair amount of debugging in
bundler_v2.zigandrenamer.zigto understand the issue well enough to identify the issue being in the parsing step. Namely, the discovery that at identifier rename time,dwas not a top-level symbol in any offoo.js's chunks. It was instead in a child scope. Thus, the performing renaming onbar.jswasn't detecting that the identifierdwas already taken by the block-scoped var infoo.js.That said, I spent much less time stepping through the
js_parser.zigstack frames and have a very limited understanding of it. The implementation may be less than ideal for all I know.How did you verify your code works?
bun-debug test test-file-name.test)I added the test @Jarred-Sumner provided based on my initial reproduction of the issue. I observed the test failing initially, and passing after the the change. Additionally, manually verifying the output looks as expected:

Zig change PR template checkboxes
I don't know if these apply or how to do/answer them.
bun-debug test test-file-name.test)