fix(bundler): preserve original specifier in require.resolve() output#27531
fix(bundler): preserve original specifier in require.resolve() output#27531
Conversation
When bundling, `require.resolve('pkg/path')` was being rewritten to use
the resolved absolute path from the build machine (e.g.,
`require.resolve("/home/user/project/node_modules/pkg/path")`). This
caused failures when running `bun build --compile` binaries on different
machines, since the hardcoded absolute path doesn't exist there.
Now uses the `original_path` field (which preserves the original import
specifier) instead of the resolved `path.text` when printing
`require.resolve()` calls.
Closes #27530
Co-Authored-By: Claude <noreply@anthropic.com>
|
Updated 12:45 PM PT - Feb 27th, 2026
❌ Your commit
🧪 To try this PR locally: bunx bun-pr 27531That installs a local version of the PR into your bun-27531 --bun |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review infoConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (2)
WalkthroughThis PR extends the Babel/JS printer to preserve original specifiers in require.resolve calls by preferring Changes
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
LGTM — straightforward fix preferring original_path over the resolved absolute path for require.resolve() output, with proper fallback and good test coverage.
Extended reasoning...
Overview
This PR fixes the bundler printer (src/js_printer.zig) to use record.original_path instead of record.path.text when emitting require.resolve() calls. The original_path field already existed on ImportRecord and was already being populated in bundle_v2.zig (line 3452-3453) before resolution overwrites the path. The fix is a simple conditional: prefer original_path when non-empty, fall back to path.text otherwise. A bundler test is added to verify the output contains original specifiers rather than absolute paths.
Security risks
None. This change only affects what string literal is emitted in the bundled output for require.resolve() calls. It does not introduce any new input handling, network access, or privilege changes.
Level of scrutiny
This is production-critical bundler code, so it warrants careful review. However, the change is minimal (9 lines of logic + comments) and the pattern is well-established — original_path was already used in MetafileBuilder.zig for a similar purpose. The fallback to path.text ensures no regression for cases where original_path is not populated.
Other factors
- The
original_pathfield is documented inimport_record.zig(line 114) and is populated during bundle resolution inbundle_v2.zig. - The test covers package specifiers, scoped packages, and subpaths, and also asserts that absolute paths from the build machine are not present.
- Existing
RequireResolve,ConditionalRequireResolve, andcompile/ResolveEmbeddedFiletests continue to pass per the PR description. - No prior reviews or outstanding comments to address.
Summary
bun build --compileproducing binaries that fail withCannot find module '/absolute/path/from/build/machine/...'when using packages likeplaywrightthat callrequire.resolve()at runtime.import_record.path.text) forrequire.resolve()calls instead of the original specifier (import_record.original_path). This hardcoded build-machine paths into the output.original_path(the specifier as written in source code, e.g."playwright-core/package.json") sorequire.resolve()resolves correctly at runtime.Closes #27530
Test plan
default/RequireResolvePreservesOriginalSpecifierbundler test that verifies original specifiers are preservedRequireResolve,ConditionalRequireResolve, andcompile/ResolveEmbeddedFiletests continue to passrequire.resolvetest passes🤖 Generated with Claude Code