diff --git a/packages/plugin-rsc/README.md b/packages/plugin-rsc/README.md index e2d11b867..5180a6448 100644 --- a/packages/plugin-rsc/README.md +++ b/packages/plugin-rsc/README.md @@ -555,6 +555,54 @@ and React client environments in the browser. ## Tips +### Stable client chunks + +You can use Rolldown's `codeSplitting.groups` option to keep React and Vite runtime code in stable client chunks. This allows browsers to reuse these chunks when application code changes. + +```ts +import { fileURLToPath } from 'node:url' +import rsc from '@vitejs/plugin-rsc' +import { defineConfig, normalizePath } from 'vite' + +const reactServerDom = normalizePath( + fileURLToPath(import.meta.resolve('@vitejs/plugin-rsc/react/browser')), +) + +export default defineConfig({ + plugins: [rsc()], + environments: { + client: { + build: { + rolldownOptions: { + output: { + codeSplitting: { + groups: [ + { + name: 'lib-react', + test(id) { + return ( + id.includes('/node_modules/react/') || + id.includes('/node_modules/react-dom/') || + id.includes(reactServerDom) + ) + }, + }, + { + name: 'lib-vite', + test: (id) => id === '\0vite/preload-helper.js', + }, + ], + }, + }, + }, + }, + }, + }, +}) +``` + +Use a function for the `lib-react` group test so the React Server Components runtime is included even when the CommonJS plugin adds a proxy suffix to its module ID, such as `?commonjs-es-import`. + ### CSS Support The plugin automatically handles CSS code-splitting and injection for server components. This eliminates the need to manually call [`import.meta.viteRsc.loadCss()`](#importmetaviterscloadcss) in most cases. diff --git a/packages/plugin-rsc/examples/basic/vite.config.ts b/packages/plugin-rsc/examples/basic/vite.config.ts index 1605d63cc..b75ce417d 100644 --- a/packages/plugin-rsc/examples/basic/vite.config.ts +++ b/packages/plugin-rsc/examples/basic/vite.config.ts @@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url' import tailwindcss from '@tailwindcss/vite' import react from '@vitejs/plugin-react' import rsc from '@vitejs/plugin-rsc' +import * as vite from 'vite' import { type Plugin, type Rollup, defineConfig, normalizePath } from 'vite' export default defineConfig({ @@ -123,29 +124,53 @@ export default defineConfig({ '@vitejs/plugin-rsc/react/browser', ) - return { - environments: { - client: { - build: { + const isReactChunk = (id: string) => + id.includes('node_modules/react/') || + id.includes('node_modules/react-dom/') || + id.includes(reactServerDom) + const isViteChunk = (id: string) => id === '\0vite/preload-helper.js' + + const build = + 'rolldownVersion' in vite + ? { + rolldownOptions: { + output: { + codeSplitting: { + groups: [ + { + name: 'lib-react', + // use a function to handle commonjs plugin proxy modules + // e.g. `(id)?commonjs-es-import` + test: isReactChunk, + }, + { + name: 'lib-vite', + test: isViteChunk, + }, + ], + }, + }, + }, + } + : { rollupOptions: { output: { - manualChunks: (id) => { - // need to use functional form to handle commonjs plugin proxy module - // e.g. `(id)?commonjs-es-import` - if ( - id.includes('node_modules/react/') || - id.includes('node_modules/react-dom/') || - id.includes(reactServerDom) - ) { + manualChunks(id: string) { + if (isReactChunk(id)) { return 'lib-react' } - if (id === '\0vite/preload-helper.js') { + if (isViteChunk(id)) { return 'lib-vite' } }, }, }, - }, + } + + return { + environments: { + client: { + build, }, }, }