Skip to content

Commit a96a6b2

Browse files
hi-ogawaclaude
andauthored
docs(rsc): mention validateImports option for build time server-only and client-only validation (#858)
Co-authored-by: Claude <[email protected]>
1 parent 0f2fbc7 commit a96a6b2

File tree

1 file changed

+72
-7
lines changed

1 file changed

+72
-7
lines changed

packages/plugin-rsc/README.md

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,17 @@ export default defineConfig({
353353
// this behavior can be customized by `serverHandler` option.
354354
serverHandler: false,
355355

356+
// the plugin provides build-time validation of 'server-only' and 'client-only' imports.
357+
// this is enabled by default. See the "server-only and client-only import" section below for details.
358+
validateImports: true,
359+
360+
// by default, the plugin uses a build-time generated encryption key for
361+
// "use server" closure argument binding.
362+
// This can be overwritten by configuring `defineEncryptionKey` option,
363+
// for example, to obtain a key through environment variable during runtime.
364+
// cf. https://nextjs.org/docs/app/guides/data-security#overwriting-encryption-keys-advanced
365+
defineEncryptionKey: 'process.env.MY_ENCRYPTION_KEY',
366+
356367
// when `loadModuleDevProxy: true`, `import.meta.viteRsc.loadModule` is implemented
357368
// through `fetch` based RPC, which allows, for example, rsc environment inside
358369
// cloudflare workers to communicate with node ssr environment on main Vite process.
@@ -362,13 +373,6 @@ export default defineConfig({
362373
// if it breaks, it can be opt-out or selectively applied based on files.
363374
rscCssTransform: { filter: (id) => id.includes('/my-app/') },
364375

365-
// by default, the plugin uses a build-time generated encryption key for
366-
// "use server" closure argument binding.
367-
// This can be overwritten by configuring `defineEncryptionKey` option,
368-
// for example, to obtain a key through environment variable during runtime.
369-
// cf. https://nextjs.org/docs/app/guides/data-security#overwriting-encryption-keys-advanced
370-
defineEncryptionKey: 'process.env.MY_ENCRYPTION_KEY',
371-
372376
// see `RscPluginOptions` for full options ...
373377
}),
374378
],
@@ -496,6 +500,67 @@ import.meta.viteRsc.loadModule
496500
497501
See also [Vite documentation](https://vite.dev/guide/api-hmr.html#intellisense-for-typescript) for `vite/client` types.
498502
503+
### `server-only` and `client-only` import
504+
505+
<!-- references? -->
506+
<!-- https://nextjs.org/docs/app/getting-started/server-and-client-components#preventing-environment-poisoning -->
507+
<!-- https://overreacted.io/how-imports-work-in-rsc/ -->
508+
509+
You can use the `server-only` import to prevent accidentally importing server-only code into client bundles, which can expose sensitive server code in public static assets.
510+
For example, the plugin will show an error `'server-only' cannot be imported in client build` for the following code:
511+
512+
- server-utils.js
513+
514+
```tsx
515+
import 'server-only'
516+
517+
export async function getData() {
518+
const res = await fetch('https://internal-service.com/data', {
519+
headers: {
520+
authorization: process.env.API_KEY,
521+
},
522+
})
523+
return res.json()
524+
}
525+
```
526+
527+
- client.js
528+
529+
```tsx
530+
'use client'
531+
import { getData } from './server-utils.js' // ❌ 'server-only' cannot be imported in client build
532+
...
533+
```
534+
535+
Similarly, the `client-only` import ensures browser-specific code isn't accidentally imported into server environments.
536+
For example, the plugin will show an error `'client-only' cannot be imported in server build` for the following code:
537+
538+
- client-utils.js
539+
540+
```tsx
541+
import 'client-only'
542+
543+
export function getStorage(key) {
544+
// This uses browser-only APIs
545+
return window.localStorage.getItem(key)
546+
}
547+
```
548+
549+
- server.js
550+
551+
```tsx
552+
import { getStorage } from './client-utils.js' // ❌ 'client-only' cannot be imported in server build
553+
554+
export function ServerComponent() {
555+
const data = getStorage("settings")
556+
...
557+
}
558+
```
559+
560+
Note that while there are official npm packages [`server-only`](https://www.npmjs.com/package/server-only) and [`client-only`](https://www.npmjs.com/package/client-only) created by React team, they don't need to be installed. The plugin internally overrides these imports and surfaces their runtime errors as build-time errors.
561+
562+
This build-time validation is enabled by default and can be disabled by setting `validateImports: false` in the plugin options.
563+
499564
## Credits
500565
501566
This project builds on fundamental techniques and insights from pioneering Vite RSC implementations.

0 commit comments

Comments
 (0)