Repository navigation
fix(bundler): copy non-JS/CSS files referenced as URL assets in HTML - #27039
Conversation
|
Updated 10:40 PM PT - Feb 15th, 2026
❌ Your commit
🧪 To try this PR locally: bunx bun-pr 27039That installs a local version of the PR into your bun-27039 --bun |
|
No actionable comments were generated in the recent review. 🎉 WalkthroughResolve 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
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
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.
20d93f5 to
7f93a7d
Compare
There was a problem hiding this comment.
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.
Code ReviewNewest first ✅ 7f93a — Looks good! Reviewed 2 files across 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>
7f93a7d to
ce890b5
Compare
…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>
…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>
Summary
<link rel="manifest" href="./manifest.json" />(and similar non-JS/CSS URL assets) resulting in 404s when usingBun.buildwith HTML entrypointsImportKind.urlimports, but the bundler was assigning the extension-based loader (e.g..json) which parses the file instead of copying it as a static asset.fileloader forImportKind.urlimports when the resolved loader wouldn'tshouldCopyForBundling()and isn't JS/CSS/HTML (which have their own handling)Test plan
html/manifest-jsontest: verifies manifest.json is copied as hashed asset and HTML href is rewrittenhtml/xml-assettest: verifies.webmanifestfiles are also handled correctlybun bd test test/bundler/bundler_html.test.ts)USE_SYSTEM_BUN=1) confirming they validate the fix🤖 Generated with Claude Code