Skip to content

fix(bundler): copy non-JS/CSS files referenced as URL assets in HTML - #27039

Merged
Jarred-Sumner merged 1 commit into
mainfrom
claude/fix-html-manifest-json-asset
Feb 17, 2026
Merged

Jarred-Sumner merged 1 commit into
mainfrom
claude/fix-html-manifest-json-asset

Conversation

@robobun

@robobun robobun commented Feb 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fix <link rel="manifest" href="./manifest.json" /> (and similar non-JS/CSS URL assets) resulting in 404s when using Bun.build with HTML entrypoints
  • The HTML scanner correctly identifies these as ImportKind.url imports, but the bundler was assigning the extension-based loader (e.g. .json) which parses the file instead of copying it as a static asset
  • Force the .file loader for ImportKind.url imports when the resolved loader wouldn't shouldCopyForBundling() and isn't JS/CSS/HTML (which have their own handling)

Test plan

  • Added html/manifest-json test: verifies manifest.json is copied as hashed asset and HTML href is rewritten
  • Added html/xml-asset test: verifies .webmanifest files are also handled correctly
  • All 20 HTML bundler tests pass (bun bd test test/bundler/bundler_html.test.ts)
  • New tests fail on system bun (USE_SYSTEM_BUN=1) confirming they validate the fix

🤖 Generated with Claude Code

@robobun

robobun commented Feb 14, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 10:40 PM PT - Feb 15th, 2026

❌ Your commit ce890b56 has 1 failures in Build #37374 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 27039

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

bun-27039 --bun

@coderabbitai

coderabbitai Bot commented Feb 14, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉


Walkthrough

Resolve loader selection for imports so URL-referenced HTML assets that would otherwise not be copy-emitted (and are not JS/CSS/HTML) are forced to use the file loader, causing them to be emitted as assets. Added tests verifying manifest.json and .webmanifest are hashed and emitted.

Changes

Cohort / File(s) Summary
Bundler Asset Loader Logic
src/bundler/bundle_v2.zig
Replaced direct assignment of import_record.loader with logic that computes a resolved_loader (from the record, path, or default) and conditionally forces .file for URL-based imports that are not copy-eligible and are not JS/CSS/HTML, ensuring these HTML-referenced assets are emitted as files.
Bundler HTML Tests
test/bundler/bundler_html.test.ts
Added tests that confirm manifest.json and site.webmanifest referenced in HTML are rewritten to hashed asset filenames (e.g., manifest-*.json, *.webmanifest) and that the emitted asset contents match expectations.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: forcing non-JS/CSS files referenced as URL assets in HTML to be copied rather than parsed.
Description check ✅ Passed The description covers the required sections with clear explanation of the problem, solution, and comprehensive test plan with verification steps.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/bundler/bundler_html.test.ts`:
- Around line 876-883: The test currently assumes the manifest href always
includes a "./" prefix which makes the regex and subsequent file read brittle;
update the assertions around htmlContent, the regex that sets manifestMatch, and
the file path resolution so they accept an optional "./" or leading "/" and
still locate the hashed filename. Specifically, change the regex used to create
manifestMatch (currently matching /href="\.\/(manifest-[a-zA-Z0-9]+\.json)"/) to
allow an optional "./" or "/" prefix (e.g.
/href="(?:\.\/|\/)?(manifest-[A-Za-z0-9]+\.json)"/), relax the not.toContain
check so it doesn't fail on absence/presence of "./", and when calling
api.readFile("out/" + manifestMatch![1]) ensure you strip any leading "./" or
"/" from the captured group (or use the captured group directly since the regex
captures only the filename) so the read path is correct.

Comment thread test/bundler/bundler_html.test.ts
@robobun
robobun force-pushed the claude/fix-html-manifest-json-asset branch from 20d93f5 to 7f93a7d Compare February 14, 2026 23:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/bundler/bundler_html.test.ts`:
- Around line 889-915: Update the itBundled test's onAfterBundle callback to
assert the emitted .webmanifest asset actually exists and has the expected
content: use the existing htmlContent (from api.readFile("out/index.html")) to
extract the rewritten href (e.g., via the /href="([^"]*\.webmanifest)"/ match),
then call api.readFile("out/" + extractedFilename) and validate its contents
(parse JSON or check it contains the original "My App" / icon path) to ensure
the asset was emitted and correct; keep everything inside the same onAfterBundle
function and reference the existing symbols htmlContent, api.readFile, and
itBundled.

Comment thread test/bundler/bundler_html.test.ts
@claude

claude Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ 7f93a — Looks good!

Reviewed 2 files across src/bundler/ and test/bundler/: This PR fixes manifest.json and other non-JS/CSS files referenced as URL assets in HTML from returning 404 errors by forcing the bundler to use the .file loader to copy them as static assets instead of parsing them.


Powered by Claude Code Review

When an HTML file references a file via a URL-type import (e.g.
`<link rel="manifest" href="./manifest.json" />`), the bundler was using
the extension-based loader (.json) which parses the file rather than
copying it. This caused the manifest.json to be missing from the output
directory, resulting in 404s.

Force the .file loader for ImportKind.url imports when the resolved
loader would not copy the file for bundling and isn't JS/CSS/HTML.

Co-Authored-By: Claude <noreply@anthropic.com>
@robobun
robobun force-pushed the claude/fix-html-manifest-json-asset branch from 7f93a7d to ce890b5 Compare February 16, 2026 06:00
@Jarred-Sumner
Jarred-Sumner merged commit 5b0db01 into main Feb 17, 2026
58 of 59 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the claude/fix-html-manifest-json-asset branch February 17, 2026 02:06
structwafel pushed a commit to structwafel/bun that referenced this pull request Apr 25, 2026
…ven-sh#27039)

## Summary

- Fix `<link rel="manifest" href="./manifest.json" />` (and similar
non-JS/CSS URL assets) resulting in 404s when using `Bun.build` with
HTML entrypoints
- The HTML scanner correctly identifies these as `ImportKind.url`
imports, but the bundler was assigning the extension-based loader (e.g.
`.json`) which parses the file instead of copying it as a static asset
- Force the `.file` loader for `ImportKind.url` imports when the
resolved loader wouldn't `shouldCopyForBundling()` and isn't JS/CSS/HTML
(which have their own handling)

## Test plan

- [x] Added `html/manifest-json` test: verifies manifest.json is copied
as hashed asset and HTML href is rewritten
- [x] Added `html/xml-asset` test: verifies `.webmanifest` files are
also handled correctly
- [x] All 20 HTML bundler tests pass (`bun bd test
test/bundler/bundler_html.test.ts`)
- [x] New tests fail on system bun (`USE_SYSTEM_BUN=1`) confirming they
validate the fix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
xhjkl pushed a commit to xhjkl/bun that referenced this pull request May 14, 2026
…ven-sh#27039)

## Summary

- Fix `<link rel="manifest" href="./manifest.json" />` (and similar
non-JS/CSS URL assets) resulting in 404s when using `Bun.build` with
HTML entrypoints
- The HTML scanner correctly identifies these as `ImportKind.url`
imports, but the bundler was assigning the extension-based loader (e.g.
`.json`) which parses the file instead of copying it as a static asset
- Force the `.file` loader for `ImportKind.url` imports when the
resolved loader wouldn't `shouldCopyForBundling()` and isn't JS/CSS/HTML
(which have their own handling)

## Test plan

- [x] Added `html/manifest-json` test: verifies manifest.json is copied
as hashed asset and HTML href is rewritten
- [x] Added `html/xml-asset` test: verifies `.webmanifest` files are
also handled correctly
- [x] All 20 HTML bundler tests pass (`bun bd test
test/bundler/bundler_html.test.ts`)
- [x] New tests fail on system bun (`USE_SYSTEM_BUN=1`) confirming they
validate the fix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants