Skip to content

perf(rsc): skip scans without server references#1269

Open
TheAlexLichter wants to merge 1 commit into
vitejs:mainfrom
TheAlexLichter:perf/rsc-skip-scans-without-server-references
Open

perf(rsc): skip scans without server references#1269
TheAlexLichter wants to merge 1 commit into
vitejs:mainfrom
TheAlexLichter:perf/rsc-skip-scans-without-server-references

Conversation

@TheAlexLichter

@TheAlexLichter TheAlexLichter commented Jun 24, 2026

Copy link
Copy Markdown
Member

This PR adds a serverReferences?: boolean option to @vitejs/plugin-rsc, letting frameworks that can prove an app has no React "use server" actions skip the expensive reference-analysis builds.

RSC frameworks often already know their app roots, route files, and source conventions, so they can conservatively scan and set either rsc({ serverReferences: false }) or top-level rsc: { serverReferences: false }.

This makes the optimization broadly useful across plugin-rsc-based frameworks.

Framework Wiring Points

Framework Where to change Wiring
vinext packages/vinext/src/index.ts Can scan project source, then pass serverReferences: earlyMayContainServerActions.
Waku packages/waku/src/lib/vite-plugins/combined-plugins.ts Add serverReferences: mayContainServerActions inside its existing rsc({ ... }) call.
TanStack Start packages/react-start-rsc/src/plugin/vite.ts Add serverReferences to the existing top-level returned rsc: { ... } config.
React Router packages/react-router-dev/vite/rsc/plugin.ts Add top-level rsc: { serverReferences: mayContainServerActions } beside its environment config.

Safety

Frameworks should only set serverReferences: false when they can conservatively determine that no React "use server" references exist.

If scanning fails, source roots are ambiguous, or server actions may come from transformed dependencies, the safe default is to leave serverReferences enabled.

Benchmark

In my vinext benchmark I got a difference from 191.3 ms (13.73% improvement).

Alternatives

  • Make the existing scan builds cheaper
    • Possible but still runs extra RSC/SSR environment builds, so less efficient
    • Many small changes => higher maintenance risk.
  • Automatic detection inside plugin-rsc
    • No: plugin-rsc does not reliably know every framework’s source roots, route conventions, virtual modules, MDX handling, or transformed dependency rules.
  • Framework-provided reference manifests
    • Much larger API surface than a boolean + tight coupling to plugin-rsc internals

@hi-ogawa hi-ogawa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is good to explore, but iirc, there is an issue with just building rsc -> client -> ssr in some framework.

Also, I'm not familiar with Vinext's own use client/server scanning, but we should confirm if that covers node_modules since user package can include the directive too.

We've had discussed some build shortcuts for tanstack with @schiller-manuel but I found we somehow needed ssr -> rsc -> client -ssr.

For framework level customization, we already have customBuildApp: false. The example looks like

rsc({
entries: {
rsc: './src/framework/entry.rsc.tsx',
},
customBuildApp: true,
}),
],
builder: {
sharedPlugins: true,
sharedConfigBuild: true,
async buildApp(builder) {
const { manager } = getPluginApi(builder.config)!
// Scan
manager.isScanBuild = true
builder.environments.rsc!.config.build.write = false
// TOOD: cannot do write = false since vite 8.0.9
// https://github.com/vitejs/vite/issues/22305
// builder.environments.client!.config.build.write = false
await builder.build(builder.environments.rsc!)
await builder.build(builder.environments.client!)
builder.environments.rsc!.config.build.write = true
builder.environments.client!.config.build.write = true
manager.isScanBuild = false
manager.stabilize()
// Build
await builder.build(builder.environments.rsc!)
await builder.build(builder.environments.client!)
// write manifest
manager.writeAssetsManifest(['rsc'])
},

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.

2 participants