Skip to content

Commit 8f98c81

Browse files
hi-ogawaclaude
andcommitted
docs(plugin-rsc): add comprehensive CSS support documentation
- Add CSS Support section explaining auto CSS injection mechanism - Document rscCssTransform feature and configuration options - Add note linking from loadCss API to CSS Support section - Include examples of component detection and transformation - Cover query parameter control and dev vs prod behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 775ac61 commit 8f98c81

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

packages/plugin-rsc/README.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ export function renderHTML(...) {}
264264
265265
#### `import.meta.viteRsc.loadCss`
266266
267+
> [!NOTE]
268+
> The plugin automatically injects CSS for React components through the `rscCssTransform` feature. See the [CSS Support](#css-support) section for detailed information about automatic CSS injection.
269+
267270
- Type: `(importer?: string) => React.ReactNode`
268271
269272
This allows collecting css which is imported through a current server module and injecting them inside server components.
@@ -436,6 +439,124 @@ This is a wrapper of `react-server-dom` API and helper API to setup a minimal RS
436439

437440
- `hydrate`
438441

442+
## CSS Support
443+
444+
The plugin provides automatic CSS code-splitting and injection for both client and server components through the `rscCssTransform` feature. This eliminates the need to manually call `import.meta.viteRsc.loadCss()` in most cases.
445+
446+
### How Auto CSS Injection Works
447+
448+
The core mechanism is implemented in the `rscCssTransform` function in `packages/plugin-rsc/src/plugin.ts`. Here's how it works:
449+
450+
1. **Component Detection**: The plugin automatically detects React components by looking for:
451+
- Function exports with capital letter names (e.g., `export function Page() {}`)
452+
- Default exports that are functions with capital names (e.g., `export default function Page() {}`)
453+
- Const exports assigned to functions with capital names (e.g., `export const Page = () => {}`)
454+
455+
2. **CSS Import Detection**: For detected components, the plugin checks if the module imports any CSS files (`.css`, `.scss`, `.sass`, etc.)
456+
457+
3. **Automatic Wrapping**: When both conditions are met, the plugin wraps the component with a CSS injection wrapper:
458+
459+
```tsx
460+
// Before transformation
461+
import './styles.css'
462+
463+
export function Page() {
464+
return <div>Hello</div>
465+
}
466+
```
467+
468+
```tsx
469+
// After transformation
470+
import './styles.css'
471+
import React from 'react'
472+
473+
export function Page() {
474+
return <div>Hello</div>
475+
}
476+
477+
function __wrapper(props) {
478+
return React.createElement(
479+
React.Fragment,
480+
null,
481+
import.meta.viteRsc.loadCss(),
482+
React.createElement(Page, props),
483+
)
484+
}
485+
Object.defineProperty(__wrapper, 'name', { value: 'Page' })
486+
export { __wrapper as Page }
487+
```
488+
489+
### Configuration
490+
491+
You can configure or disable the auto CSS injection feature:
492+
493+
```js
494+
// vite.config.ts
495+
export default defineConfig({
496+
plugins: [
497+
rsc({
498+
// Disable auto CSS injection entirely
499+
rscCssTransform: false,
500+
501+
// Or configure with a custom filter
502+
rscCssTransform: {
503+
filter: (id) => {
504+
// Only apply to files in specific directories
505+
return id.includes('/components/') || id.includes('/pages/')
506+
},
507+
},
508+
}),
509+
],
510+
})
511+
```
512+
513+
### Manual Control with Query Parameters
514+
515+
For fine-grained control, you can use the `?vite-rsc-css-export=<name>` query parameter:
516+
517+
```tsx
518+
// my-component.tsx?vite-rsc-css-export=MyComponent
519+
import './styles.css'
520+
521+
export function MyComponent() {
522+
return <div>Only this component gets CSS injection</div>
523+
}
524+
525+
export function AnotherComponent() {
526+
return <div>This one doesn't</div>
527+
}
528+
```
529+
530+
You can also specify multiple component names:
531+
532+
```tsx
533+
// my-components.tsx?vite-rsc-css-export=ComponentA,ComponentB
534+
```
535+
536+
### Development vs Production
537+
538+
- **Development**: CSS injection happens dynamically to support HMR (Hot Module Replacement)
539+
- **Production**: CSS dependencies are collected during build and injected as `<link>` tags in the HTML
540+
541+
### Manual CSS Loading
542+
543+
For cases where you need manual control, you can still use `import.meta.viteRsc.loadCss()`:
544+
545+
```tsx
546+
export function Layout() {
547+
return (
548+
<html>
549+
<head>
550+
{/* Load CSS for specific routes */}
551+
{import.meta.viteRsc.loadCss('/routes/home.tsx')}
552+
{import.meta.viteRsc.loadCss('/routes/about.tsx')}
553+
</head>
554+
<body>...</body>
555+
</html>
556+
)
557+
}
558+
```
559+
439560
## Credits
440561

441562
This project builds on fundamental techniques and insights from pioneering Vite RSC implementations.

0 commit comments

Comments
 (0)