Skip to content

fix(bundler): include CSS in all HTML entrypoints sharing a deduplicated CSS chunk - #27040

Merged
Jarred-Sumner merged 2 commits into
mainfrom
claude/fix-shared-css-production-23668
Feb 15, 2026
Merged

Jarred-Sumner merged 2 commits into
mainfrom
claude/fix-shared-css-production-23668

Conversation

@robobun

@robobun robobun commented Feb 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes When the --production flag is used, CSS is not included correctly when there are multiple html entrypoints #23668: When multiple HTML entrypoints shared the same CSS file with --production, only the first HTML file included the <link> tag for CSS. The second (and subsequent) entrypoints were missing it entirely.
  • Root cause was two bugs in CSS chunk handling:
    1. getCSSChunkForHTML matched by entry_point_id, but deduplicated CSS chunks only stored the first entry point's ID. Fixed by resolving CSS chunks through the JS chunk's css_chunks indices.
    2. CSS chunk index remapping in computeChunks used js_chunks.count() as the base offset, not accounting for interleaved HTML chunks. Fixed by using sorted_chunks.len.

Test plan

  • New test html/SharedCSSProductionMultipleEntries in test/bundler/bundler_html.test.ts — verifies both HTML entrypoints get CSS <link> tags pointing to the same deduplicated CSS chunk
  • Test fails with USE_SYSTEM_BUN=1 (reproduces the bug) and passes with debug build (confirms the fix)
  • All 19 existing HTML bundler tests continue to pass

🤖 Generated with Claude Code

@robobun

robobun commented Feb 14, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 2:17 AM PT - Feb 15th, 2026

❌ Your commit f0cae21a has 2 failures in Build #37342 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 27040

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

bun-27040 --bun

@coderabbitai

coderabbitai Bot commented Feb 14, 2026 •

Copy link
Copy Markdown
Contributor

Walkthrough

Resolve CSS deduplication and HTML linking: CSS chunk lookup for HTML now prefers the related JS chunk's css_chunks (with fallback to entry_point_id), and CSS chunk remapping iterates over sorted chunks to handle interleaved HTML/JS. Adds a regression test for shared CSS across multiple production HTML entries.

Changes

Cohort / File(s) Summary
CSS chunk resolution
src/bundler/Chunk.zig
getCSSChunkForHTML now attempts to find the related JS chunk and returns its first referenced CSS chunk via css_chunks; falls back to prior entry_point_id matching when absent.
CSS deduplication & remapping
src/bundler/linker_context/computeChunks.zig
Always compute CSS dedup key from content/order (remove conditional on css_chunking). Adjust remapping loop to use sorted_chunks.len as start index to account for interleaved HTML/JS chunks.
Tests
test/bundler/bundler_html.test.ts, test/bundler/esbuild/css.test.ts
Add SharedCSSProductionMultipleEntries regression test verifying deduplicated CSS is linked by multiple production HTML entries; re-enable the previously skipped MetafileCSSBundleTwoToOne test.
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (11 files):

⚔️ src/bundler/Chunk.zig (content)
⚔️ src/bundler/linker_context/computeChunks.zig (content)
⚔️ src/runtime.js (content)
⚔️ test/bundler/__snapshots__/bun-build-api.test.ts.snap (content)
⚔️ test/bundler/bundler_edgecase.test.ts (content)
⚔️ test/bundler/bundler_html.test.ts (content)
⚔️ test/bundler/bundler_npm.test.ts (content)
⚔️ test/bundler/bundler_promiseall_deadcode.test.ts (content)
⚔️ test/bundler/esbuild/css.test.ts (content)
⚔️ test/bundler/html-import-manifest.test.ts (content)
⚔️ test/regression/issue/cyclic-imports-async-bundler.test.js (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly describes the main fix: ensuring CSS is included in all HTML entrypoints when sharing deduplicated CSS chunks, which matches the core objective from issue #23668.
Description check ✅ Passed The PR description comprehensively covers both the root causes of the bugs and the test plan, exceeding the basic template requirements with detailed technical explanations.
Linked Issues check ✅ Passed The code changes directly address issue #23668 by fixing CSS chunk association for multiple HTML entrypoints through two targeted bug fixes: resolving CSS chunks via JS chunk indices and correcting index remapping.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the CSS deduplication issue: modifications to getCSSChunkForHTML, computeChunks logic, test additions, and unskipping a related test are all in scope.

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


No actionable comments were generated in the recent review. 🎉


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

…ted CSS chunk

When multiple HTML entrypoints shared the same CSS file with `--production`,
only the first HTML file included the `<link>` tag. This was caused by two issues:

1. `getCSSChunkForHTML` matched CSS chunks by `entry_point_id`, but deduplicated
   CSS chunks only stored the first entry point's ID. Fixed by looking up CSS
   chunks through the JS chunk's `css_chunks` indices instead.

2. The CSS chunk index remapping used `js_chunks.count()` as the starting offset,
   which didn't account for HTML chunks interleaved with JS chunks in the sorted
   array. Fixed by using `sorted_chunks.len` instead.

Closes #23668

Co-Authored-By: Claude <noreply@anthropic.com>
@robobun
robobun force-pushed the claude/fix-shared-css-production-23668 branch from 630f8b2 to d1a0e9a Compare February 14, 2026 23:46
@claude

claude Bot commented Feb 14, 2026 •

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ 630f8 — Looks good!

Reviewed 3 files across src/bundler/ and test/bundler/: This PR fixes CSS chunk index calculation when multiple HTML entry points share CSS files, ensuring the correct CSS chunks are referenced from their corresponding JavaScript chunks.


Powered by Claude Code Review

@claude

claude Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ d1a0e — Looks good!

Reviewed 10 files across src/bundler/, src/bun.js/, src/js/builtins/, and test/: Fixes CSS chunk handling in the bundler to ensure all HTML entrypoints include link tags for shared CSS files in production builds.


Powered by Claude Code Review

…oints

Use content-based hashing for CSS chunk deduplication even when
css_chunking is disabled. This prevents "Multiple files share the same
output path" errors when multiple JS entry points import the same CSS
and hash-based entry naming is used.

Unskips the css/MetafileCSSBundleTwoToOne test.

Co-Authored-By: Claude <noreply@anthropic.com>
@claude

claude Bot commented Feb 15, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ f0cae — Looks good!

Reviewed 2 files across src/bundler/ and test/bundler/: fixes CSS bundling bug where multiple HTML entrypoints sharing deduplicated CSS chunks would only emit the CSS link tag in the first HTML file, by resolving CSS chunks through the JS chunk's indirection table and correcting the CSS chunk index remapping offset.


Powered by Claude Code Review

@Jarred-Sumner
Jarred-Sumner merged commit 70b354a into main Feb 15, 2026
57 of 59 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the claude/fix-shared-css-production-23668 branch February 15, 2026 11:36
structwafel pushed a commit to structwafel/bun that referenced this pull request Apr 25, 2026
xhjkl pushed a commit to xhjkl/bun that referenced this pull request May 14, 2026
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.

When the --production flag is used, CSS is not included correctly when there are multiple html entrypoints

2 participants