Skip to content

feat: Support import styles from './index.module.css'#625

Merged
justinvdm merged 100 commits intomainfrom
support-importing-styles
Jul 31, 2025
Merged

feat: Support import styles from './index.module.css'#625
justinvdm merged 100 commits intomainfrom
support-importing-styles

Conversation

@justinvdm
Copy link
Copy Markdown
Collaborator

@justinvdm justinvdm commented Jul 30, 2025

This change adds support for importing stylesheets directly into client components, allowing developers to use import './styles.css' or import styles from './styles.module.css' inside "use client" modules.

Problem

The framework did not previously have a mechanism to handle CSS imports within "use client" components.

The core issue stems from the framework's architecture, which uses a dynamic, server-rendered Document.tsx component and React Server Components (RSC). This differs from a standard Vite application in two key ways:

  1. No Static Entry Point: Vite cannot analyze a static index.html file to discover all CSS dependencies during a build.
  2. Dynamic Dependencies: The full list of components, and therefore their CSS dependencies, is only revealed as the RSC stream is rendered on the server.

As a result, there was no way to discover stylesheets imported by client components during a request. This meant that in a production build, these styles would be missing from the final HTML, and the development-time behavior was not suitable for a server-rendered application.

Solution

This change introduces a two-phase process designed to discover client-side script dependencies during a request and inject their associated stylesheets.

  1. Script Discovery: At runtime, all client-side JavaScript modules required for the page are collected into a list. This includes static entry points found in Document.tsx and dynamic components rendered as part of the RSC stream.

  2. Stylesheet Injection: Once the list of scripts is available, their CSS dependencies are looked up and injected in an environment-specific way.

    • In production, a static build manifest is used to find the final asset URLs, which are injected via <link> tags.
    • In development, the styles are injected via inline <style> tags. Each tag includes a data-vite-dev-id attribute, which makes it compatible with Vite's Hot Module Replacement (HMR) system while preventing a Flash of Unstyled Content.

For more, check out the Architecture Doc.

Testing

This change adds smoke tests to validate the new stylesheet handling functionality. Like the other smoke tests, these checks are done for both dev and deployments.

The test cases cover:
- Direct CSS imports in "use client" components (e.g., import styles from './styles.module.css').
- CSS URL imports in Document.tsx (e.g., import href from './styles.css?url').
- Hot Module Replacement (HMR) for both import types to check that style changes are applied in dev

edit: Skipped for now, as only works for headed browsers

Links

Fixes #617

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Jul 30, 2025

Deploying redwood-sdk-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9f10599
Status: ✅  Deploy successful!
Preview URL: https://84af112b.redwood-sdk-docs.pages.dev
Branch Preview URL: https://support-importing-styles.redwood-sdk-docs.pages.dev

View logs

@justinvdm justinvdm marked this pull request as ready for review July 30, 2025 23:24
@justinvdm justinvdm merged commit b839158 into main Jul 31, 2025
5 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.

Support CSS modules in server components

1 participant