Skip to content

fix(server-functions): ship server components' stylesheets in production - #486

Merged
ryansolid merged 2 commits into
nextfrom
claude/project-thread-fdizuj-456
Oct 28, 2026
Merged

ryansolid merged 2 commits into
nextfrom
claude/project-thread-fdizuj-456

Conversation

@ryansolid

Copy link
Copy Markdown
Member

Fixes #456.

Problem

With serverFunctions: { components: true }, the client compile replaces a 'use server' module with createServerReference stubs. Everything that module imported therefore drops out of the client graph. A stylesheet reached only through a server component got no client asset and no manifest entry, so the production document linked nothing for it and the component rendered unstyled. Frame navigation had the same problem. Dev looked right, because its CSS crawl walks the SSR graph, which hid the bug.

Change

In a client build with components on, transformModule now collects the stylesheets a 'use server' module reaches and appends side-effect imports for them to the client stub. The new helper is src/server-functions/server-styles.ts:

  • The original module's import specifiers are read with this.parse(code, { lang: 'tsx' }), skipping type-only imports, and resolved in the client environment.
  • Stylesheets are collected, but only ambient ones: ?url, ?inline and ?raw imports are skipped.
  • Every other module is visited with this.load(), and the walk follows importedIds, so dependencies in node_modules are covered too. Loading runs the module's transforms, so compile-time CSS plugins such as StyleX record their rules (the case from the issue thread). The module is never imported, so its code stays out of the client bundle.
  • A nested 'use server' module loads as its own stub, which carries its own stylesheet imports.

The stylesheets then land in the client chunk that imports the stub (the entry CSS in the example), so the SSR document links them. Dev is unchanged, since its crawl already handles this, and builds without components skip the walk entirely.

Tests

  • start-ssr frames mode: src/frames/data.tsx now renders PanelBadge, a component imported only below the boundary, which imports panel-badge.css. A new browser check asserts that its computed color is applied.
    • Without the fix: frames-prod fails the check and frames-dev passes, matching the issue.
    • With the fix: both pass.
  • After a SOLID_SERVER_COMPONENTS=1 build, dist/client contains the rule in the entry CSS, and none of the server text (SERVER-ROW-TEXT, server-styled, PanelBadge). The suite's existing secret scan also passes.
  • vitest run passes (71), tsc --noEmit is clean, and the full start-ssr suite passes (779/779).

Generated by Claude Code

…ion (#456)

The client compile replaces a 'use server' module with references, so the
stylesheets it reached never joined the client graph. Dev's CSS crawl
walks the SSR graph, so only production rendered server components
unstyled. With components on, the client build now walks the module's
imports (scripts are loaded, never imported) and imports the stylesheets
it finds from the client module.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0117BoWNQHxQ9311k7tQMEKs
@changeset-bot

changeset-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f3e568b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/vite-plugin Patch

Not sure what this means? Click here to learn what changesets are.

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

@pkg-pr-new

pkg-pr-new Bot commented Oct 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/vite-plugin@486

commit: f3e568b

@ryansolid
ryansolid merged commit f0e2dab into next Oct 28, 2026
6 checks passed
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.

2 participants