Skip to content

Commit 8aaab1b

Browse files
hi-ogawaclaude
andauthored
feat(rsc): add customBuildApp option (#1052)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 35004e3 commit 8aaab1b

File tree

3 files changed

+92
-27
lines changed

3 files changed

+92
-27
lines changed

packages/plugin-rsc/examples/no-ssr/vite.config.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fsp from 'node:fs/promises'
22
import react from '@vitejs/plugin-react'
3-
import rsc from '@vitejs/plugin-rsc'
3+
import rsc, { getPluginApi } from '@vitejs/plugin-rsc'
44
import { defineConfig, type Plugin } from 'vite'
55

66
export default defineConfig({
@@ -11,8 +11,34 @@ export default defineConfig({
1111
entries: {
1212
rsc: './src/framework/entry.rsc.tsx',
1313
},
14+
customBuildApp: true,
1415
}),
1516
],
17+
builder: {
18+
sharedPlugins: true,
19+
sharedConfigBuild: true,
20+
async buildApp(builder) {
21+
const { manager } = getPluginApi(builder.config)!
22+
23+
// Scan
24+
manager.isScanBuild = true
25+
builder.environments.rsc!.config.build.write = false
26+
builder.environments.client!.config.build.write = false
27+
await builder.build(builder.environments.rsc!)
28+
await builder.build(builder.environments.client!)
29+
builder.environments.rsc!.config.build.write = true
30+
builder.environments.client!.config.build.write = true
31+
manager.isScanBuild = false
32+
manager.stabilize()
33+
34+
// Build
35+
await builder.build(builder.environments.rsc!)
36+
await builder.build(builder.environments.client!)
37+
38+
// write manifest
39+
manager.writeAssetsManifest(['rsc'])
40+
},
41+
},
1642
})
1743

1844
function spaPlugin(): Plugin[] {

packages/plugin-rsc/src/plugin.ts

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ function resolvePackage(name: string) {
106106

107107
export type { RscPluginManager }
108108

109+
/**
110+
* @experimental
111+
*/
109112
class RscPluginManager {
110113
server!: ViteDevServer
111114
config!: ResolvedConfig
@@ -127,6 +130,21 @@ class RscPluginManager {
127130
toRelativeId(id: string): string {
128131
return normalizePath(path.relative(this.config.root, id))
129132
}
133+
134+
writeAssetsManifest(environmentNames: string[]): void {
135+
// write client manifest to all non-client builds during post-build step.
136+
// this makes each server build to be self-contained and deploy-able for cloudflare.
137+
const assetsManifestCode = `export default ${serializeValueWithRuntime(
138+
this.buildAssetsManifest,
139+
)}`
140+
for (const name of environmentNames) {
141+
const manifestPath = path.join(
142+
this.config.environments[name]!.build.outDir,
143+
BUILD_ASSETS_MANIFEST_NAME,
144+
)
145+
fs.writeFileSync(manifestPath, assetsManifestCode)
146+
}
147+
}
130148
}
131149

132150
export type RscPluginOptions = {
@@ -186,6 +204,14 @@ export type RscPluginOptions = {
186204
*/
187205
useBuildAppHook?: boolean
188206

207+
/**
208+
* Skip the default buildApp orchestration and expose utilities on `builder.rsc`
209+
* for downstream frameworks to implement custom build pipelines.
210+
* @experimental
211+
* @default false
212+
*/
213+
customBuildApp?: boolean
214+
189215
/**
190216
* Custom environment configuration
191217
* @experimental
@@ -343,7 +369,7 @@ export default function vitePluginRsc(
343369
manager.stabilize()
344370
logStep('[4/4] build client environment...')
345371
await builder.build(builder.environments.client!)
346-
writeAssetsManifest(['rsc'])
372+
manager.writeAssetsManifest(['rsc'])
347373
return
348374
}
349375

@@ -399,27 +425,23 @@ export default function vitePluginRsc(
399425
fs.renameSync(tempRscOutDir, rscOutDir)
400426
}
401427

402-
writeAssetsManifest(['ssr', 'rsc'])
403-
}
404-
405-
function writeAssetsManifest(environmentNames: string[]) {
406-
// output client manifest to non-client build directly.
407-
// this makes server build to be self-contained and deploy-able for cloudflare.
408-
const assetsManifestCode = `export default ${serializeValueWithRuntime(
409-
manager.buildAssetsManifest,
410-
)}`
411-
for (const name of environmentNames) {
412-
const manifestPath = path.join(
413-
manager.config.environments[name]!.build.outDir,
414-
BUILD_ASSETS_MANIFEST_NAME,
415-
)
416-
fs.writeFileSync(manifestPath, assetsManifestCode)
417-
}
428+
manager.writeAssetsManifest(['ssr', 'rsc'])
418429
}
419430

420431
let hasReactServerDomWebpack = false
421432

422433
return [
434+
{
435+
name: 'rsc:builder-api',
436+
buildApp: {
437+
order: 'pre' as const,
438+
async handler(builder) {
439+
builder.rsc = {
440+
manager,
441+
}
442+
},
443+
},
444+
},
423445
{
424446
name: 'rsc',
425447
async config(config, env) {
@@ -539,15 +561,17 @@ export default function vitePluginRsc(
539561
},
540562
},
541563
},
542-
builder: {
543-
sharedPlugins: true,
544-
sharedConfigBuild: true,
545-
async buildApp(builder) {
546-
if (!rscPluginOptions.useBuildAppHook) {
547-
await buildApp(builder)
548-
}
549-
},
550-
},
564+
builder: rscPluginOptions.customBuildApp
565+
? undefined
566+
: {
567+
sharedPlugins: true,
568+
sharedConfigBuild: true,
569+
async buildApp(builder) {
570+
if (!rscPluginOptions.useBuildAppHook) {
571+
await buildApp(builder)
572+
}
573+
},
574+
},
551575
}
552576
},
553577
configResolved() {
@@ -557,6 +581,9 @@ export default function vitePluginRsc(
557581
},
558582
buildApp: {
559583
async handler(builder) {
584+
if (rscPluginOptions.customBuildApp) {
585+
return
586+
}
560587
if (rscPluginOptions.useBuildAppHook) {
561588
await buildApp(builder)
562589
}

packages/plugin-rsc/types/index.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ declare module 'vite' {
1717
/** Options for `@vitejs/plugin-rsc` */
1818
rsc?: import('@vitejs/plugin-rsc').RscPluginOptions
1919
}
20+
21+
interface ViteBuilder {
22+
/**
23+
* RSC plugin API exposed for custom build pipelines.
24+
* Available when using `rsc({ customBuildApp: true })`.
25+
* @experimental
26+
*/
27+
rsc: {
28+
/** Access to internal RscPluginManager for controlling build phases */
29+
manager: import('@vitejs/plugin-rsc').RscPluginManager
30+
}
31+
}
2032
}
2133

2234
export {}

0 commit comments

Comments
 (0)