From c10792f95ef75aa95e55d6ad59758bae80e2c14e Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 1 Aug 2025 11:57:23 +0900 Subject: [PATCH 1/3] refactor(rsc): move `writeManifest` inside `buildApp` hook --- packages/plugin-rsc/src/plugin.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index a8b946ea2..6ce13b327 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -180,6 +180,25 @@ export default function vitePluginRsc( serverResourcesMetaMap = sortObject(serverResourcesMetaMap) await builder.build(builder.environments.client!) await builder.build(builder.environments.ssr!) + + if (rscPluginOptions.useBuildAppHook) { + writeAssetsManifest() + } + } + + function writeAssetsManifest() { + // output client manifest to non-client build directly. + // this makes server build to be self-contained and deploy-able for cloudflare. + const assetsManifestCode = `export default ${serializeValueWithRuntime( + buildAssetsManifest, + )}` + for (const name of ['ssr', 'rsc']) { + const manifestPath = path.join( + config.environments[name]!.build.outDir, + BUILD_ASSETS_MANIFEST_NAME, + ) + fs.writeFileSync(manifestPath, assetsManifestCode) + } } return [ @@ -711,7 +730,10 @@ export default function vitePluginRsc( writeBundle() { // TODO: move this to `buildApp`. // note that we already do this in buildApp for no-ssr case. - if (this.environment.name === 'ssr') { + if ( + !rscPluginOptions.useBuildAppHook && + this.environment.name === 'ssr' + ) { // output client manifest to non-client build directly. // this makes server build to be self-contained and deploy-able for cloudflare. const assetsManifestCode = `export default ${serializeValueWithRuntime( From 3ffe73549191c42a0182999c36d4df548b2a9691 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 1 Aug 2025 13:03:17 +0900 Subject: [PATCH 2/3] refactor --- packages/plugin-rsc/src/plugin.ts | 40 ++++--------------------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/packages/plugin-rsc/src/plugin.ts b/packages/plugin-rsc/src/plugin.ts index 6ce13b327..6ae8cd354 100644 --- a/packages/plugin-rsc/src/plugin.ts +++ b/packages/plugin-rsc/src/plugin.ts @@ -153,15 +153,7 @@ export default function vitePluginRsc( clientReferenceMetaMap = sortObject(clientReferenceMetaMap) serverResourcesMetaMap = sortObject(serverResourcesMetaMap) await builder.build(builder.environments.client!) - - const assetsManifestCode = `export default ${serializeValueWithRuntime( - buildAssetsManifest, - )}` - const manifestPath = path.join( - builder.environments!.rsc!.config.build!.outDir!, - BUILD_ASSETS_MANIFEST_NAME, - ) - fs.writeFileSync(manifestPath, assetsManifestCode) + writeAssetsManifest(['rsc']) return } @@ -180,19 +172,16 @@ export default function vitePluginRsc( serverResourcesMetaMap = sortObject(serverResourcesMetaMap) await builder.build(builder.environments.client!) await builder.build(builder.environments.ssr!) - - if (rscPluginOptions.useBuildAppHook) { - writeAssetsManifest() - } + writeAssetsManifest(['ssr', 'rsc']) } - function writeAssetsManifest() { + function writeAssetsManifest(environmentNames: string[]) { // output client manifest to non-client build directly. // this makes server build to be self-contained and deploy-able for cloudflare. const assetsManifestCode = `export default ${serializeValueWithRuntime( buildAssetsManifest, )}` - for (const name of ['ssr', 'rsc']) { + for (const name of environmentNames) { const manifestPath = path.join( config.environments[name]!.build.outDir, BUILD_ASSETS_MANIFEST_NAME, @@ -727,27 +716,6 @@ export default function vitePluginRsc( } return }, - writeBundle() { - // TODO: move this to `buildApp`. - // note that we already do this in buildApp for no-ssr case. - if ( - !rscPluginOptions.useBuildAppHook && - this.environment.name === 'ssr' - ) { - // output client manifest to non-client build directly. - // this makes server build to be self-contained and deploy-able for cloudflare. - const assetsManifestCode = `export default ${serializeValueWithRuntime( - buildAssetsManifest, - )}` - for (const name of ['ssr', 'rsc']) { - const manifestPath = path.join( - config.environments[name]!.build.outDir, - BUILD_ASSETS_MANIFEST_NAME, - ) - fs.writeFileSync(manifestPath, assetsManifestCode) - } - } - }, }, createVirtualPlugin('vite-rsc/bootstrap-script-content', function () { assert(this.environment.name !== 'client') From e90463b6e9f9edb85b9e526611e63f91080f2729 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 1 Aug 2025 14:06:38 +0900 Subject: [PATCH 3/3] chore: fix ssg example --- packages/plugin-rsc/examples/ssg/vite.config.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/plugin-rsc/examples/ssg/vite.config.ts b/packages/plugin-rsc/examples/ssg/vite.config.ts index 05807fd2f..b84ad62f3 100644 --- a/packages/plugin-rsc/examples/ssg/vite.config.ts +++ b/packages/plugin-rsc/examples/ssg/vite.config.ts @@ -21,6 +21,7 @@ export default defineConfig((env) => ({ ssr: './src/framework/entry.ssr.tsx', }, serverHandler: env.isPreview ? false : undefined, + useBuildAppHook: true, }), rscSsgPlugin(), inspect(), @@ -38,15 +39,9 @@ function rscSsgPlugin(): Plugin[] { } } }, - // Use post ssr writeBundle to wait for app is fully built. - // On Vite 7, you can use `buildApp` hook instead. - writeBundle: { - order: 'post', - async handler() { - if (this.environment.name === 'ssr') { - const config = this.environment.getTopLevelConfig() - await renderStatic(config) - } + buildApp: { + async handler(builder) { + await renderStatic(builder.config) }, }, },