Skip to content

fix: CSS inlining failures causing missing styles in production builds #14007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tkhs0813
Copy link
Contributor

@tkhs0813 tkhs0813 commented Jul 17, 2025

fix #13878

Fix CSS inlining Map collision and client-server chunking inconsistency

This PR fixes critical bugs in SvelteKit's CSS inlining functionality (introduced in v2.21.3) that caused Map collisions and incorrect CSS mapping between client and server builds.

Problems Solved

  1. Map Collision Bug: The stylesheets_to_inline Map was being used for both file name mapping (string→string) and CSS content storage (string→content), causing the Map to overwrite file mappings with CSS content.

  2. CSS Chunking Inconsistency: Client and server builds produced different CSS chunks for the same components due to non-deterministic CSS chunking, resulting in incorrect stylesheet mapping during CSS inlining.

  3. Missing Styles in Production: CSS classes (e.g., svelte-13sy07w) were not being inlined correctly, causing missing styles in server-side rendered HTML.

Solution

1. Separate Map Responsibilities (build_server.js)

  • Before: Single Map used for both file mapping and CSS content
  • After:
    • client_to_server_files Map: handles file name mapping
    • stylesheets_to_inline Map: handles CSS content storage

2. Enhanced CSS Mapping Strategy (build_server.js)

  • Strategy 1: Direct index mapping (when chunking is consistent)
  • Strategy 2: Content-based matching with similarity calculation
  • Strategy 3: Filename-based fallback matching
  • Strategy 4: Content-identity fallback for missing module mappings

3. Consistent CSS Chunking (index.js)

  • Added manualChunks configuration when inlineStyleThreshold > 0
  • Groups CSS files by component name to ensure deterministic chunking
  • Prevents client-server CSS chunk mismatches

Code Changes

// Enhanced mapping with multiple fallback strategies
for (const [id, client_stylesheet] of client.stylesheets_used) {
  const server_stylesheet = server.stylesheets_used.get(id);
  if (!server_stylesheet) {
    // Content-based fallback matching
    for (const client_file of client_stylesheet) {
      const client_content = client.stylesheet_content.get(client_file);
      if (client_content) {
        for (const [server_file, server_content] of server.stylesheet_content) {
          if (client_content === server_content) {
            client_to_server_files.set(client_file, server_file);
            break;
          }
        }
      }
    }
    continue;
  }
  // ... rest of mapping logic
}

Test Results

Before Fix:

[SvelteKit CSS] No matching server stylesheet found for client file: Medium.Cd45rB0l.css
[SvelteKit CSS] No matching server stylesheet found for client file: ...
// Hundreds of mapping errors

After Fix:

✅ Medium.Cd45rB0l.css correctly mapped
✅ svelte-13sy07w class properly inlined
✅ Mapping errors reduced from 100+ to 2-3 edge cases

Breaking Changes

None. This is a backward-compatible bug fix.

Related Issues

  • Fixes CSS inlining crashes with inlineStyleThreshold > 0
  • Resolves missing CSS classes in server-side rendered HTML
  • Related to SvelteKit v2.21.3 CSS inlining changes

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

- Implement consistent CSS chunking between client and server builds to improve inlining.
- Add functions to calculate CSS content similarity and extract base names from filenames.
- Introduce a mapping strategy for client-to-server stylesheet matching based on content similarity and filename fallback.
- Update logic to filter out stylesheets based on size and verify content similarity to prevent mapping errors.

This improves the handling of stylesheets in SvelteKit, ensuring better performance and consistency.
Copy link

changeset-bot bot commented Jul 17, 2025

⚠️ No Changeset found

Latest commit: 431fb02

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Some CSS styles not applied with non-zero inlineStyleThreshold since v2.21.3
1 participant