### Monorepo Setup and Build Commands Source: https://github.com/vitejs/vite-plugin-react/blob/main/AGENTS.md Use these commands for initial project setup and building within the monorepo. Refer to CONTRIBUTING.md for detailed setup instructions. ```bash pnpm install && pnpm build ``` ```bash pnpm dev ``` ```bash pnpm test ``` -------------------------------- ### Partial-object synthesis examples Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-member-chain-optional-computed-follow-up.md Examples demonstrating how partial-object synthesis is handled for plain member paths versus computed access. ```js { y: { z: x.y.z } } ``` ```js x[k].z ``` -------------------------------- ### Install @vitejs/plugin-react-swc Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/README.md Install the plugin as a development dependency. ```sh npm i -D @vitejs/plugin-react-swc ``` -------------------------------- ### Example with Intermediate Reads Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-rsc-member-chain-binding-plan.md This example shows how the approach preserves semantics for broader intermediate reads. When `config.api` and `config.api.key` are captured, the antichain dedupe keeps `config.api`, resulting in a bound object `{ api: config.api }`. ```javascript return [config.api.key, Object.keys(config.api)] ``` -------------------------------- ### Fixture Input Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-04-scope-unit-tests.md A sample JavaScript file used as input for scope analysis testing. ```js function outer() { const value = 0 function action() { if (true) { const value = 1 return value } } } ``` -------------------------------- ### Configure React dependencies Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Examples for specifying React versions in package.json, including canary/experimental channels or specific version pins. ```json { "dependencies": { "react": "canary", "react-dom": "canary", "react-server-dom-webpack": "canary" } } ``` ```json { "dependencies": { "react": "19.2.3", "react-dom": "19.2.3", "react-server-dom-webpack": "19.2.3" } } ``` -------------------------------- ### Basic Integration Test Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/CONTRIBUTING.md This is an example of a basic integration test using the provided test utilities. It assumes the `page` object is available and imported from '~utils'. ```javascript import { page } from '~utils' test('should work', async () => { expect(await page.textContent('.foo')).toMatch('foo') }) ``` -------------------------------- ### Example: Computed Access Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-member-chain-optional-computed-follow-up.md Demonstrates a computed access pattern where the property key is an expression, necessitating the capture of the expression itself. ```javascript x[y].z ``` -------------------------------- ### Example: Optional Chaining Access Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-member-chain-optional-computed-follow-up.md Illustrates an optional chaining access pattern that requires richer metadata than the current BindPath supports. ```javascript x?.y.z ``` -------------------------------- ### Action-Local Computed Key Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-member-chain-optional-computed-follow-up.md Illustrates a computed key expression ('key') that is local to the action function itself. ```javascript function outer() { let obj = {} async function action() { 'use server' let key = 'x' return obj[key] } } ``` -------------------------------- ### Run Vite RSC development and production commands Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/examples/starter/README.md Standard CLI commands for starting the development server and building the project for production. ```sh # run dev server npm run dev # build for production and preview npm run build npm run preview ``` -------------------------------- ### Basic Vite React Plugin Configuration Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md Standard setup for integrating the React plugin into your Vite configuration file. ```javascript import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], }) ``` -------------------------------- ### Future API Import Considerations Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Examples of current and future API patterns for environment-aware imports. ```ts import.meta.viteRsc.import('./entry.ssr', { environment: 'ssr' }) ``` ```ts import('./entry.ssr', { with: { environment: 'ssr' } }) ``` ```ts import.meta.viteRsc.import('./entry.ssr', { environment: 'ssr' }) // returns module import.meta.viteRsc.importAsset('./entry.browser', { asset: 'client' }) // returns string ``` -------------------------------- ### Create Vite Project with RSC Template Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Use this command to create a new Vite project with the RSC template pre-configured. This is the recommended starting point for new projects. ```sh npm create vite@latest -- --template rsc ``` -------------------------------- ### Demonstrate Hoisting Behavior Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-04-hoist-variable-shadowing.md Example of how variable hoisting can lead to incorrect scope resolution if lookup is performed eagerly. ```javascript function action() { console.log({ foo }) { var foo = 123 } } ``` -------------------------------- ### Class scope declaration Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/oxc.md Example of a class declaration used to illustrate scope creation. ```javascript class Foo extends Base {} ``` -------------------------------- ### Render React App with Vite Source: https://github.com/vitejs/vite-plugin-react/blob/main/playground/react-classic/index.html Standard way to render a React application using ReactDOM.createRoot. Ensure React and ReactDOM are installed. ```jsx import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' ReactDOM.createRoot(document.getElementById('app')).render( React.createElement(App), ) ``` -------------------------------- ### Initialize and run Vite RSC React Router project Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/examples/react-router/README.md Commands to scaffold the project, install dependencies, and execute development, build, and preview tasks. Includes specific commands for Cloudflare deployment. ```sh npx giget gh:vitejs/vite-plugin-react/packages/plugin-rsc/examples/react-router my-app cd my-app npm i npm run dev npm run build npm run preview # run on @cloudflare/vite-plugin and deploy. # a separate configuration is found in ./cf/vite.config.ts npm run cf-dev npm run cf-build npm run cf-preview npm run cf-release ``` -------------------------------- ### Scaffold RSC project with giget Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/examples/basic/README.md Use this command to initialize a new project from the official Vite React RSC basic example template. ```sh npx giget gh:vitejs/vite-plugin-react/packages/plugin-rsc/examples/basic my-app ``` -------------------------------- ### Access RSC loadModule API Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Example usage of the loadModule API available via import.meta. ```ts import.meta.viteRsc.loadModule // ^^^^^^^^^^ // (environmentName: string, entryName?: string) => Promise ``` -------------------------------- ### Define Environment Import Manifests Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Example structure of the generated manifest files for RSC and SSR environments, mapping source paths to dynamic imports. ```typescript // dist/rsc/__vite_rsc_env_imports_manifest.js (for RSC → SSR) export default { '/abs/path/entry.ssr.tsx': () => import('../ssr/entry.ssr.js'), } // dist/ssr/__vite_rsc_env_imports_manifest.js (for SSR → RSC) export default { '/abs/path/entry.rsc.tsx': () => import('../rsc/index.js'), } ``` -------------------------------- ### Define RSC Environment Imports Manifest Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Example of the generated manifest file structure using static import functions. ```ts // __vite_rsc_env_imports_manifest.js (generated in buildApp after SSR build) export default { '/abs/path/to/entry.ssr.tsx': () => import('../ssr/entry.ssr.js'), } ``` -------------------------------- ### Outer-Scope Computed Key Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-member-chain-optional-computed-follow-up.md Shows a scenario where the computed key expression ('key') is captured from an outer scope. ```javascript function outer() { let key = 'x' let obj = {} async function action() { 'use server' return obj[key] } } ``` -------------------------------- ### React App Rendering with ReactDOM Source: https://github.com/vitejs/vite-plugin-react/blob/main/playground/include-node-modules/index.html Standard method for rendering a React application into the DOM using ReactDOM. Ensure you have React and ReactDOM installed. ```javascript import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' ReactDOM.createRoot(document.getElementById('app')).render( React.createElement(App) ) ``` -------------------------------- ### Plain Member Chain Capture Test Case Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-rsc-member-chain-binding-plan.md A test case for capturing a plain member chain. This example demonstrates how 'config.api.key' is handled. ```javascript function outer() { const config = { api: { key: 'x' } } async function action() { 'use server' return config.api.key } } ``` -------------------------------- ### Lifecycle Integration: buildStart for @vitejs/plugin-rsc Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-02-16-issue-1109-server-asset-copy-plan.md Resets the client asset handle set for the current build environment when the build starts. ```typescript buildStart (for each build env): reset handle set. ``` -------------------------------- ### Server Action Transformation Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/nextjs.md Illustrates the transformation of a React component with a server action, showing how outer-scope variables are handled for serialization. This is relevant for understanding closure variable capture in server environments. ```javascript // input export function Page() { const api_key = 'secret' async function action() { 'use server' console.log(api_key) } } // output (simplified) export const $$RSC_SERVER_ACTION_0 = async function action( $$ACTION_CLOSURE_BOUND, ) { const [$$ACTION_ARG_0] = await decryptActionBoundArgs( '...', $$ACTION_CLOSURE_BOUND, ) console.log($$ACTION_ARG_0) } export function Page() { const api_key = 'secret' var action = $$RSC_SERVER_ACTION_0.bind( null, encryptActionBoundArgs('...', api_key), ) } ``` -------------------------------- ### RSC Server Action Binding Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-rsc-member-chain-binding-plan.md Demonstrates how a server action is transformed to bind specific closure captures, like config.api.key, using .bind(null, ...). The bound arguments are evaluated at render time on the server and must be React-serializable. ```javascript const action = $$register($$hoist_0_action, ...).bind(null, config.api.key) ``` -------------------------------- ### Synthetic-Local Approach: Single Path Binding Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-rsc-member-chain-binding-plan.md Example of the synthetic-local approach binding a single path. It binds the exact captured leaf value and rewrites the body to use synthetic locals. ```javascript .bind(null, config.api.key) export async function $$hoist_0_action($$hoist_arg_0) { "use server" return $$hoist_arg_0 } ``` -------------------------------- ### Run Dev Server and Build Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/examples/starter-extra/README.md Commands to run the dev server, build for production, and preview the production build. ```sh # run dev server npm run dev # build for production and preview npm run build npm run preview ``` -------------------------------- ### Register Entries via buildStart Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Alternative approaches for registering entries during the buildStart hook of the target environment. ```ts // During buildStart of target environment buildStart() { if (this.environment.name === 'ssr') { const entries = Object.values(manager.environmentImportMetaMap) .filter(m => m.targetEnv === 'ssr') for (const meta of entries) { // Add to input dynamically? Or use emitFile? } } } ``` ```ts // In target environment (ssr) buildStart for (const meta of discoveredEntries) { this.emitFile({ type: 'chunk', id: meta.resolvedId, name: meta.entryName, }) } ``` -------------------------------- ### Run Vite project commands Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/examples/ssg/README.md Standard commands for local development, production builds, and previewing the generated static site. ```js pnpm dev pnpm build pnpm preview ``` -------------------------------- ### Initialize React Root Source: https://github.com/vitejs/vite-plugin-react/blob/main/playground/react/index.html Mounts the main App component to the DOM element with the ID 'app'. Ensure the target element exists in your HTML file. ```javascript import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' ReactDOM.createRoot(document.getElementById('app')).render( React.createElement(App), ) ``` -------------------------------- ### Use SWC Plugins Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/README.md Integrate SWC plugins for build-time transformations. ```ts react({ plugins: [['@swc/plugin-styled-components', {}]] }) ``` -------------------------------- ### oxc-walker Named Function Expression Scope Pattern Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/oxc-walker.md Example of how oxc-walker represents nested scopes for named function expressions. ```text "" → (outer scope) "0" → { f: ScopeTrackerFunction } ← function name scope "0-0" → { param: ScopeTrackerFunctionParam, ... } ← params scope "0-0-0"→ (body BlockStatement scope) ``` -------------------------------- ### Basic Vite Configuration with @vitejs/plugin-react-swc Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/README.md Integrate the plugin into your Vite configuration file. ```ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react-swc' export default defineConfig({ plugins: [react()], }) ``` -------------------------------- ### Development and Testing Commands Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/CONTRIBUTING.md Common CLI commands for building, type checking, and executing E2E tests within the project environment. ```bash # Build packages pnpm dev # pnpm -C packages/plugin-rsc dev # Type check pnpm -C packages/plugin-rsc tsc-dev # Run examples pnpm -C packages/plugin-rsc/examples/basic dev # build / preview pnpm -C packages/plugin-rsc/examples/starter dev # build / preview # Run all e2e tests pnpm -C packages/plugin-rsc test-e2e # Run with UI (this allows filtering interactively) pnpm -C packages/plugin-rsc test-e2e --ui # Run specific test file pnpm -C packages/plugin-rsc test-e2e basic # Run with filter/grep pnpm -C packages/plugin-rsc test-e2e -g "hmr" # Test projects created with `setupInlineFixture` are locally runnable. For example: pnpm -C packages/plugin-rsc/examples/e2e/temp/react-compiler dev ``` -------------------------------- ### Manual transformIndexHtml for SSR with Express Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/README.md Manually call `transformIndexHtml` during SSR for equivalent initialization code. This example demonstrates usage with an Express server. ```javascript app.get('/', async (req, res, next) => { try { let html = fs.readFileSync(path.resolve(root, 'index.html'), 'utf-8') // Transform HTML using Vite plugins. html = await viteServer.transformIndexHtml(req.url, html) res.send(html) } catch (e) { return next(e) } }) ``` -------------------------------- ### Initialize HMR Runtime with Preamble Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/README.md Import this package in your client entry point for SSR applications that do not use the `transformIndexHtml` API to initialize the HMR runtime. ```javascript // [entry.client.js] import '@vitejs/plugin-react-swc/preamble' ``` -------------------------------- ### Client Environment: loadBootstrapScriptContent Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Provides raw JavaScript code to execute a browser entry file. Intended for use with React DOM SSR APIs like renderToReadableStream. ```APIDOC ## `import.meta.viteRsc.loadBootstrapScriptContent("index")` ### Description This function provides raw JavaScript code to execute a browser entry file specified by `environments.client.build.rollupOptions.input.index`. It is intended to be used with React DOM SSR APIs, such as `renderToReadableStream`. ### Usage Example ```js import { renderToReadableStream } from 'react-dom/server.edge' const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent('index') const htmlStream = await renderToReadableStream(reactNode, { bootstrapScriptContent, }) ``` ### Available On - `client` environment ``` -------------------------------- ### API Comparison: loadModule vs import Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Compares the current loadModule API with the proposed import API, highlighting differences in argument handling and DX. ```typescript const ssrModule = await import.meta.viteRsc.loadModule< typeof import('./entry.ssr.tsx') >('ssr', 'index') ``` ```typescript const ssrModule = await import.meta.viteRsc.import< typeof import('./entry.ssr.tsx') >('./entry.ssr', { environment: 'ssr' }) ``` -------------------------------- ### Class Scope Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/eslint-scope.md Demonstrates how a class declaration creates two scopes: an outer scope where the class name is declared, and an inner ClassScope for self-reference. ```javascript class Foo extends Base {} // outer scope ← Foo defined here (ClassDeclaration) // └── ClassScope ← Foo also defined here (inner self-reference) ``` -------------------------------- ### SemanticBuilder API Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/oxc.md Demonstrates how to instantiate and configure the SemanticBuilder to perform semantic analysis on a program. ```APIDOC ## SemanticBuilder API ### Description Builds a `SemanticBuilder` instance, configures syntax error checking and control flow analysis, and then builds the semantic analysis results for a given program. ### Method `SemanticBuilder::new()` ### Endpoint N/A (Rust API) ### Parameters #### Query Parameters - **`with_check_syntax_error`** (bool) - Optional - Enables or disables syntax error checking. - **`with_cfg`** (bool) - Optional - Enables or disables control flow graph generation. ### Request Body N/A ### Request Example ```rust let program = parse("..."); // Assuming 'parse' returns an AST program let builder = SemanticBuilder::new() .with_check_syntax_error(true) .with_cfg(false) .build(&program); let SemanticBuilderReturn { semantic, errors } = builder; ``` ### Response #### Success Response (200) - **`semantic`** (Semantic) - The resulting semantic analysis object. - **`errors`** (Vec) - A list of errors encountered during analysis. #### Response Example ```json { "semantic": { ... }, "errors": [ ... ] } ``` ``` -------------------------------- ### Synthetic-Local Approach: Multiple Paths Binding Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-rsc-member-chain-binding-plan.md Demonstrates the synthetic-local approach for binding multiple paths. Each captured value is bound as a separate argument. ```javascript .bind(null, config.api.key, config.user.name) export async function $$hoist_0_action($$hoist_arg_0, $$hoist_arg_1) { return [$$hoist_arg_0, $$hoist_arg_1] } ``` -------------------------------- ### Named Function Expression Scope Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/eslint-scope.md Illustrates the scope structure created by a named function expression. The outer scope contains the function name, and an inner scope holds parameters and variable declarations. ```javascript // (function f() {}) creates: // 1. FunctionExpressionNameScope { variables: [Variable{name:"f"}] } // 2. FunctionScope { variables: [params...] } ``` -------------------------------- ### Transform Manifest Lookup Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Shows the transformation from original import syntax to manifest-based lookup. ```ts // Original: await import.meta.viteRsc .import('./entry.ssr', { environment: 'ssr' })( // Build transform to: await import('./__vite_rsc_env_imports_manifest.js'), ) .default['/abs/path/to/entry.ssr.tsx']() ``` -------------------------------- ### Default Parameter with Var Hoisting Bug Example Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-scope-manager-research.md Illustrates a spec violation where default parameter expressions incorrectly resolve `var` declarations within the same function scope. This can lead to incorrect closure variable capture in server actions. ```javascript function outer() { const y = 'outer' async function action() { 'use server' function inner(x = y) { // which `y` does this resolve to? var y = 'inner' // hoisted to inner's function scope } } } ``` -------------------------------- ### Synthesize Partial Object from Path Set Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-rsc-member-chain-binding-plan.md This example demonstrates how to build a nested object literal from a deduplicated path set. It serializes a path tree (trie) into an object literal string, where each leaf node represents the original source expression. ```javascript ["api", "key"] → api: { key: config.api.key } ["user", "name"] → user: { name: config.user.name } merged → { api: { key: config.api.key }, user: { name: config.user.name } } ``` -------------------------------- ### Essential Commands for @vitejs/plugin-rsc Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/AGENTS.md Standard commands for building, type-checking, and testing the plugin within the packages/plugin-rsc directory. ```bash # inside packages/plugin-rsc directory pnpm build # build package pnpm tsc # typecheck pnpm dev # Watch mode development pnpm test-e2e # Run e2e tests pnpm test-e2e basic # Test specific example ``` -------------------------------- ### Resolve Member Access Chains in Server Actions Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/nextjs.md Illustrates how Next.js tracks full member access paths like `config.api.key` for server actions, allowing for more granular binding compared to just the base identifier. ```javascript async function action() { 'use server' console.log(config.api.key) // → Name(config_id, [.api, .key]) } ``` -------------------------------- ### Configure React Refresh Host for Module Federation Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc/README.md In a module federation setup, specify the host origin to ensure Hot Module Replacement (HMR) works correctly between remote and host applications. This updates the React Fast Refresh runtime URL. ```js react({ reactRefreshHost: 'http://localhost:3000' }) ``` -------------------------------- ### Using Different React Versions Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Configuration details for using different versions of React and `react-server-dom-webpack` with the plugin. ```APIDOC ## Using Different React Versions ### Description By default, `@vitejs/plugin-rsc` includes a vendored version of `react-server-dom-webpack`. If `react-server-dom-webpack` is present in your project's dependencies, the plugin will use it automatically, allowing flexibility with React versions. ### Configuration Examples **Canary or Experimental Versions:** ```json { "dependencies": { "react": "canary", "react-dom": "canary", "react-server-dom-webpack": "canary" } } ``` **Specific Versions (e.g., for security updates):** ```json { "dependencies": { "react": "19.2.3", "react-dom": "19.2.3", "react-server-dom-webpack": "19.2.3" } } ``` ``` -------------------------------- ### Vite Plugin React var Hoisting Implementation Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/periscopic.md Demonstrates Vite Plugin React's approach to var hoisting, which is handled at walk time rather than declaration-adding time. ```javascript const target = node.kind === 'var' ? current.getNearestFunctionScope() : current ``` -------------------------------- ### Initialize RSC Plugin Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Configures the RSC plugin within the Vite configuration, including entry points, server handlers, and import validation. ```js import rsc from '@vitejs/plugin-rsc' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ rsc({ // this is only a shorthand of specifying each rollup input via // `environments[name].build.rollupOptions.input.index` entries: { rsc: '...', ssr: '...', client: '...', }, // by default, the plugin sets up middleware // using `default` export of `rsc` environment `index` entry. // this behavior can be customized by `serverHandler` option. serverHandler: false, // the plugin provides build-time validation of 'server-only' and 'client-only' imports. // this is enabled by default. See the "server-only and client-only import" section below for details. validateImports: true, // by default, the plugin uses a build-time generated encryption key for // "use server" closure argument binding. // This can be overwritten by configuring `defineEncryptionKey` option, // for example, to obtain a key through environment variable during runtime. // cf. https://nextjs.org/docs/app/guides/data-security#overwriting-encryption-keys-advanced defineEncryptionKey: 'process.env.MY_ENCRYPTION_KEY', // when `loadModuleDevProxy: true`, `import.meta.viteRsc.loadModule` is implemented // through `fetch` based RPC, which allows, for example, rsc environment inside // cloudflare workers to communicate with node ssr environment on main Vite process. loadModuleDevProxy: true, // by default, `loadCss()` helper is injected based on certain heuristics. // if it breaks, it can be opt-out or selectively applied based on files. rscCssTransform: { filter: (id) => id.includes('/my-app/') }, // see `RscPluginOptions` for full options ... }), ], // the same options can be also specified via top-level `rsc` property. // this allows other plugin to set options via `config` hook. rsc: { // ... }, }) ``` -------------------------------- ### Resolve dependency warnings in frameworks Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Fixes for dependency resolution warnings when using the plugin within a framework package by updating optimizeDeps.include. ```sh Failed to resolve dependency: @vitejs/plugin-rsc/vendor/react-server-dom/client.browser, present in client 'optimizeDeps.include' ``` ```js // package name is "my-rsc-framework" export default function myRscFrameworkPlugin() { return { name: 'my-rsc-framework:config', configEnvironment(_name, config) { if (config.optimizeDeps?.include) { config.optimizeDeps.include = config.optimizeDeps.include.map( (entry) => { if (entry.startsWith('@vitejs/plugin-rsc')) { entry = `my-rsc-framework > ${entry}` } return entry }, ) } }, } } ``` -------------------------------- ### Review Scope Fixtures Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/scripts/README.md Commands to generate Markdown review packets for specific scope fixture categories. ```bash cd packages/plugin-rsc node ./scripts/review-scope-fixtures.ts | code - node ./scripts/review-scope-fixtures.ts shadowing import | code - node ./scripts/review-scope-fixtures.ts var-hoisting --output /tmp/scope-review.md ``` ```bash cd packages/plugin-rsc node ./scripts/review-scope-fixtures.ts typescript-eslint/destructuring --output /tmp/destructuring.md node ./scripts/review-scope-fixtures.ts typescript-eslint/import typescript-eslint/export --output /tmp/module-syntax.md node ./scripts/review-scope-fixtures.ts typescript-eslint/class typescript-eslint/jsx --output /tmp/class-jsx.md ``` -------------------------------- ### Import and Use Counter in MDX Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/examples/ssg/src/posts/counter.mdx Shows the necessary import statement and the usage of the Counter component within an MDX file. Ensure the Counter component is correctly exported from its source file. ```javascript export const title = 'Counter in MDX' import { Counter } from '../counter' # Counter in MDX ``` -------------------------------- ### Import TypeScript-ESLint Scope Fixtures Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/scripts/README.md Commands to regenerate the pre-transpiled JS fixture subtree from a local typescript-eslint checkout. ```bash cd packages/plugin-rsc node ./scripts/import-typescript-eslint-scope-fixtures.ts pnpm test -- scope.test.ts --update ``` ```bash cd packages/plugin-rsc node ./scripts/import-typescript-eslint-scope-fixtures.ts \ --source /path/to/typescript-eslint/packages/scope-manager/tests/fixtures pnpm test -- scope.test.ts --update ``` ```bash cd packages/plugin-rsc TYPESCRIPT_ESLINT_SCOPE_FIXTURES_DIR=/path/to/typescript-eslint/packages/scope-manager/tests/fixtures \ node ./scripts/import-typescript-eslint-scope-fixtures.ts pnpm test -- scope.test.ts --update ``` -------------------------------- ### oxc_semantic Data Model (Rust) Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/oxc.md Illustrates the Struct-of-Arrays (SoA) data model used in oxc_semantic for efficient symbol, scope, and reference management. ```rust // Core output (Scoping / ScopingInner) // Symbols — parallel arrays indexed by SymbolId symbol_spans: Vec // source position symbol_flags: Vec // var/let/const/class/fn/import/TS variants… symbol_scope_ids: Vec // declaring scope symbol_declarations: Vec // declaring AST node symbol_names: ArenaVec // string-interned names (arena allocator) resolved_references: ArenaVec> // per-symbol reference lists symbol_redeclarations: FxHashMap> // lazy, only if redeclared // Scopes — parallel arrays indexed by ScopeId parent_ids: Vec> node_ids: Vec flags: Vec bindings: IndexVec> // name → SymbolId per scope // References // per-node reference struct: Reference { node_id: NodeId // the IdentifierReference AST node symbol_id: Option // resolved target; None = unresolved scope_id: ScopeId // scope where the reference appears flags: ReferenceFlags // Read | Write | Type | ValueAsType | Namespace } root_unresolved_references: ArenaIdentHashMap> // globals ``` -------------------------------- ### Identify Hardcoded Filename Issues Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Demonstrates the limitation of hardcoded filenames when using custom entryFileNames configurations. ```ts // renderChunk - current implementation const targetFileName = `${entryName}.js` // ❌ Breaks with custom entryFileNames ``` -------------------------------- ### Configure Source Resolution Order Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/scripts/README.md Defines the priority order for resolving the typescript-eslint source directory. ```bash 1. --source /path/to/typescript-eslint/packages/scope-manager/tests/fixtures 2. TYPESCRIPT_ESLINT_SCOPE_FIXTURES_DIR 3. ../typescript-eslint/packages/scope-manager/tests/fixtures ``` -------------------------------- ### analyze(tree, options) Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/eslint-scope.md The primary entry point for performing scope analysis on an AST. ```APIDOC ## analyze(tree, options) ### Description Analyzes the provided AST tree to generate a ScopeManager instance. ### Parameters - **tree** (Object) - Required - The AST to analyze. - **options** (Object) - Optional - Configuration options for the analysis. ### Response - **ScopeManager** (Object) - The resulting scope manager containing scope data. ``` -------------------------------- ### Using @vitejs/plugin-rsc as Framework Package Dependencies Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Guidance on how to configure `optimizeDeps.include` when `@vitejs/plugin-rsc` is part of a framework package's dependencies. ```APIDOC ## Using `@vitejs/plugin-rsc` as a Framework Package's `dependencies` ### Description When `@vitejs/plugin-rsc` is not directly available at the project root (e.g., installed via a framework package), you might encounter resolution warnings. This section provides a solution by updating `optimizeDeps.include` to correctly reference `@vitejs/plugin-rsc` through your framework package. ### Solution Example Add a Vite plugin to your `vite.config.js` to modify `optimizeDeps.include`: ```js // Assuming your framework package name is "my-rsc-framework" export default function myRscFrameworkPlugin() { return { name: 'my-rsc-framework:config', configEnvironment(_name, config) { if (config.optimizeDeps?.include) { config.optimizeDeps.include = config.optimizeDeps.include.map( (entry) => { if (entry.startsWith('@vitejs/plugin-rsc')) { entry = `my-rsc-framework > ${entry}` } return entry }, ) } }, } } ``` ``` -------------------------------- ### Import Preamble for SSR Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md Import the preamble from `@vitejs/plugin-react/preamble` in your client entrypoint for SSR applications that do not use the `transformIndexHtml` API. ```javascript // [entry.client.js] import '@vitejs/plugin-react/preamble' ``` -------------------------------- ### Apply Build Mode Transform Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Replacement logic for generating manifest lookups during the build process. ```ts // Build mode transform const manifestImport = `await import('./__vite_rsc_env_imports_manifest.js')` replacement = `(${manifestImport}).default[${JSON.stringify(resolvedId)}]()` ``` -------------------------------- ### Implement renderChunk Logic Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-01-16-vitersc-import.md Rewrites import markers to relative paths during the renderChunk phase. ```ts for (const match of code.matchAll( /["']__vite_rsc_import__:([\s\S]*?)__["']/dg, )) { const { fromEnv, toEnv, entryName } = JSON.parse(match[1]) // Look up actual output filename from emitted chunks const targetFileName = `${entryName}.js` // or lookup from manifest const importPath = normalizeRelativePath( path.relative( path.join( config.environments[fromEnv].build.outDir, chunk.fileName, '..', ), path.join(config.environments[toEnv].build.outDir, targetFileName), ), ) s.overwrite(start, end, `(import(${JSON.stringify(importPath)}))`) } ``` -------------------------------- ### Configure Vite for RSC environments Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md Defines the plugin and environment-specific build configurations for RSC, SSR, and client entry points. ```typescript import rsc from '@vitejs/plugin-rsc' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ // add plugin rsc(), ], // specify entry point for each environment. environments: { // `rsc` environment loads modules with `react-server` condition. // this environment is responsible for: // - RSC stream serialization (React VDOM -> RSC stream) // - server functions handling rsc: { build: { rollupOptions: { input: { index: './src/framework/entry.rsc.tsx', }, }, }, }, // `ssr` environment loads modules without `react-server` condition. // this environment is responsible for: // - RSC stream deserialization (RSC stream -> React VDOM) // - traditional SSR (React VDOM -> HTML string/stream) ssr: { build: { rollupOptions: { input: { index: './src/framework/entry.ssr.tsx', }, }, }, }, // client environment is used for hydration and client-side rendering // this environment is responsible for: // - RSC stream deserialization (RSC stream -> React VDOM) // - traditional CSR (React VDOM -> Browser DOM tree mount/hydration) // - refetch and re-render RSC // - calling server functions client: { build: { rollupOptions: { input: { index: './src/framework/entry.browser.tsx', }, }, }, }, }, }) ``` -------------------------------- ### Sketch of Two-Phase Scope Tree Construction Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-04-hoist-variable-shadowing.md Conceptual outline for separating scope creation from reference collection to improve resolution accuracy. ```typescript function buildScopeTree(ast: Program): ScopeTree { // pass 1: create scopes, declare names, hoist `var` } function collectReferences(ast: Program, scopeTree: ScopeTree): void { // pass 2: walk only read/reference positions // for each Identifier read: // 1. resolve owner scope // 2. store identifier -> owner scope // 3. append identifier to enclosing function scope's references } ``` -------------------------------- ### Integrating React Compiler with Vite Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md Set up Vite to use the React Compiler by combining @vitejs/plugin-react with @rolldown/plugin-babel and the reactCompilerPreset. ```javascript // vite.config.js import { defineConfig } from 'vite' import react, { reactCompilerPreset } from '@vitejs/plugin-react' import babel from '@rolldown/plugin-babel' export default defineConfig({ plugins: [react(), babel({ presets: [reactCompilerPreset()] })], }) ``` -------------------------------- ### Partial-Object Binding for Member Chains Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/2026-04-05-rsc-member-chain-binding-plan.md Illustrates the chosen design for RSC member-chain binding. It shows how to bind specific paths from a root object by synthesizing a partial object at the call site, rather than binding the entire root object. ```javascript function Page() { const config = getConfig() async function action() { 'use server' return config.api.key } } // Output: function Page() { const config = getConfig() const action = $$register($$hoist_0_action, '', '$$hoist_0_action').bind( null, { api: { key: config.api.key } }, ) } export async function $$hoist_0_action(config) { 'use server' return config.api.key } ``` -------------------------------- ### Available on `ssr` environment Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md APIs specifically available when the environment is set to 'ssr'. -------------------------------- ### Available on `rsc` environment Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md APIs specifically available when the environment is set to 'rsc'. ```APIDOC ### Available on `rsc` environment #### `import.meta.viteRsc.loadCss` > [!NOTE] > The plugin automatically injects CSS for server components. See the [CSS Support](#css-support) section for detailed information about automatic CSS injection. - Type: `(importer?: string) => React.ReactNode` This allows collecting css which is imported through a current server module and injecting them inside server components. ```tsx import './test.css' import dep from './dep.tsx' export function ServerPage() { // this will include css assets for "test.css" // and any css transitively imported through "dep.tsx" return ( <> {import.meta.viteRsc.loadCss()} ... ) } ``` When specifying `loadCss()`, it will collect css through the server module resolved by ``. ```tsx // virtual:my-framework-helper export function Assets() { return <> {import.meta.viteRsc.loadCss("/routes/home.tsx")} {import.meta.viteRsc.loadCss("/routes/about.tsx")} {...} } // user-app.tsx import { Assets } from "virtual:my-framework-helper"; export function UserApp() { return ... } ``` ``` -------------------------------- ### Scope API Methods Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/babel-traverse.md A collection of methods for binding lookups, scope hierarchy navigation, binding mutations, and UID generation. ```APIDOC ## Scope API Methods ### Description Provides access to binding lookups, scope hierarchy navigation, and variable mutation within the AST. ### Binding Lookup - **scope.getBinding(name)**: Returns Binding | undefined. Walks parent chain to find a binding. - **scope.getOwnBinding(name)**: Returns Binding | undefined. Looks for a binding in the current scope. - **scope.hasBinding(name, opts?)**: Returns boolean. Checks if a binding exists in the scope chain. - **scope.hasOwnBinding(name)**: Returns boolean. Checks if a binding exists in the current scope. - **scope.parentHasBinding(name, opts?)**: Returns boolean. Checks if a binding exists in parent scopes. ### Scope Hierarchy - **scope.getProgramParent()**: Returns Scope. Returns the program-level scope. - **scope.getFunctionParent()**: Returns Scope | null. Returns the nearest function scope. - **scope.getBlockParent()**: Returns Scope. Returns the nearest block scope. ### Binding Mutation - **scope.registerBinding(kind, path)**: Registers a new binding. - **scope.removeBinding(name)**: Removes a binding. - **scope.moveBindingTo(name, scope)**: Moves a binding to a different scope. - **scope.rename(oldName, newName?)**: Renames a binding across all references. - **scope.push({ id, init?, kind? })**: Injects a new variable declaration into the scope. ### UID Generation - **scope.generateUid(name?)**: Returns string. Generates a unique identifier name. - **scope.generateUidIdentifier(name?)**: Returns t.Identifier. Generates a unique identifier node. ### Plugin Data - **scope.setData(key, val)**: Sets data on the scope. - **scope.getData(key)**: Returns any. Retrieves data from the scope. ``` -------------------------------- ### Including MDX Files with React Plugin Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md Configure the React plugin to enable Fast Refresh for MDX files by adjusting the 'include' option. ```javascript import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import mdx from '@mdx-js/rollup' export default defineConfig({ plugins: [ { enforce: 'pre', ...mdx() }, react({ include: /\.(mdx|js|jsx|ts|tsx)$/ }), ], }) ``` -------------------------------- ### Vite RSC Plugin Build Sequence Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/bundler-comparison.md The sequential scan phases required by the multi-graph approach in Vite. ```text RSC scan → SSR scan → RSC build → Client build → SSR build ``` -------------------------------- ### Environment Helper API Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/README.md The plugin provides an additional helper for multi-environment interaction, available on 'rsc' or 'ssr' environments. ```APIDOC ## Environment Helper API The plugin provides an additional helper for multi-environment interaction. ### Available on `rsc` or `ssr` environment #### `import.meta.viteRsc.loadModule` - Type: `(environmentName: "ssr" | "rsc", entryName?: string) => Promise` This allows importing `ssr` environment module specified by `environments.ssr.build.rollupOptions.input[entryName]` inside `rsc` environment and vice versa. When `entryName` is omitted, the function automatically uses the single entry from the target environment's `rollupOptions.input`. During development, by default, this API assumes both `rsc` and `ssr` environments execute under the main Vite process as `RunnableDevEnvironment`. Internally, `loadModule` uses the global `__VITE_ENVIRONMENT_RUNNER_IMPORT__` function to import modules in the target environment (see [`__VITE_ENVIRONMENT_RUNNER_IMPORT__`](#__vite_environment_runner_import__) below). When enabling `rsc({ loadModuleDevProxy: true })` plugin option, the loaded module is implemented as a proxy with `fetch`-based RPC to call in node environment on the main Vite process, which for example, allows `rsc` environment inside cloudflare workers to access `ssr` environment on the main Vite process. This proxy mechanism uses [turbo-stream](https://github.com/jacob-ebey/turbo-stream) for serializing data types beyond JSON, with custom encoders/decoders to additionally support `Request` and `Response` instances. During production build, this API will be rewritten into a static import of the specified entry of other environment build and the modules are executed inside the same runtime. For example, ```js // ./entry.rsc.tsx const ssrModule = await import.meta.viteRsc.loadModule("ssr", "index"); ssrModule.renderHTML(...); // ./entry.ssr.tsx (with environments.ssr.build.rollupOptions.input.index = "./entry.ssr.tsx") export function renderHTML (...) {} ``` #### `import.meta.viteRsc.import` - Type: `(specifier: string, options: { environment: string }) => Promise` A more ergonomic alternative to `loadModule`: 1. No manual `rollupOptions.input` config needed - entries are auto-discovered 2. Specifier matches the path in `typeof import(...)` type annotations **Comparison:** ```ts // Before (loadModule) - requires vite.config.ts: // environments.ssr.build.rollupOptions.input = { index: './entry.ssr.tsx' } import.meta.viteRsc.loadModule('ssr', 'index') // After (import) - no config needed, auto-discovered import.meta.viteRsc.import( './entry.ssr.tsx', { environment: 'ssr' }, ) ``` During development, this works the same as `loadModule`, using the `__VITE_ENVIRONMENT_RUNNER_IMPORT__` function to import modules in the target environment. During production build, the plugin auto-discovers these imports and emits them as entries in the target environment. A manifest file (`__vite_rsc_env_imports_manifest.js`) is generated to map module specifiers to their output filenames. ``` -------------------------------- ### Hoisting var declarations Source: https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-rsc/docs/notes/scope-manager-research/babel-traverse.md Demonstrates how non-block-scoped declarations and loop-based var declarations are registered to the nearest function or program parent. ```ts // non-block-scoped declarations: const parent = path.scope.getFunctionParent() || path.scope.getProgramParent() parent.registerDeclaration(path) // var in for-loop: const parentScope = scope.getFunctionParent() || scope.getProgramParent() parentScope.registerBinding('var', declar) ```