Skip to content

fix(bundler): preserve original specifier in require.resolve() output#27531

Open
robobun wants to merge 1 commit intomainfrom
claude/fix-require-resolve-absolute-path-27530
Open

fix(bundler): preserve original specifier in require.resolve() output#27531
robobun wants to merge 1 commit intomainfrom
claude/fix-require-resolve-absolute-path-27530

Conversation

@robobun
Copy link
Collaborator

@robobun robobun commented Feb 27, 2026

Summary

  • Fixes bun build --compile producing binaries that fail with Cannot find module '/absolute/path/from/build/machine/...' when using packages like playwright that call require.resolve() at runtime.
  • The bundler's printer was using the resolved absolute path (import_record.path.text) for require.resolve() calls instead of the original specifier (import_record.original_path). This hardcoded build-machine paths into the output.
  • Now uses original_path (the specifier as written in source code, e.g. "playwright-core/package.json") so require.resolve() resolves correctly at runtime.

Closes #27530

Test plan

  • Added default/RequireResolvePreservesOriginalSpecifier bundler test that verifies original specifiers are preserved
  • Test fails with system bun (confirms the bug) and passes with the fix
  • Existing RequireResolve, ConditionalRequireResolve, and compile/ResolveEmbeddedFile tests continue to pass
  • Transpiler require.resolve test passes

🤖 Generated with Claude Code

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>
@robobun
Copy link
Collaborator Author

robobun commented Feb 27, 2026

Updated 12:45 PM PT - Feb 27th, 2026

❌ Your commit 6a506d78 has 3 failures in Build #38283 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 27531

That installs a local version of the PR into your bun-27531 executable, so you can run:

bun-27531 --bun
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6e317c8 and 6a506d7.

📒 Files selected for processing (2)
  • src/js_printer.zig
  • test/bundler/esbuild/default.test.ts

Walkthrough

This PR extends the Babel/JS printer to preserve original specifiers in require.resolve calls by preferring path_to_print over hardcoded absolute paths, and adds tests to verify this behavior in bundled output.

Changes

Cohort / File(s) Summary
Printer Implementation
src/js_printer.zig
Modified require.resolve argument handling to use path_to_print (original specifier) instead of falling back to absolute paths from the import record, ensuring runtime resolution uses the original specifier rather than a hardcoded path.
Test Coverage
test/bundler/esbuild/default.test.ts
Added new test case default/RequireResolvePreservesOriginalSpecifier that verifies require.resolve calls in bundles preserve original specifier strings (e.g., "my-pkg/package.json", "@scope/my-pkg/subpath") rather than absolute node_modules paths.
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: preserving original specifiers in require.resolve() output during bundling.
Description check ✅ Passed The description covers both required sections from the template: what the PR does (fixes require.resolve with absolute paths) and how it was verified (test plan with multiple test cases).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_path field is documented in import_record.zig (line 114) and is populated during bundle resolution in bundle_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, and compile/ResolveEmbeddedFile tests continue to pass per the PR description.
  • No prior reviews or outstanding comments to address.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1 participant