@@ -8,6 +8,7 @@ import { createRequestListener } from '@mjackson/node-fetch-server'
88import * as esModuleLexer from 'es-module-lexer'
99import MagicString from 'magic-string'
1010import {
11+ type BuilderOptions ,
1112 type DevEnvironment ,
1213 type EnvironmentModuleNode ,
1314 type Plugin ,
@@ -123,11 +124,64 @@ export type RscPluginOptions = {
123124 * @default true
124125 */
125126 validateImports ?: boolean
127+
128+ /**
129+ * use `Plugin.buildApp` hook (introduced on Vite 7) instead of `builder.buildApp` configuration
130+ * for better composability with other plugins.
131+ * @default false
132+ */
133+ useBuildAppHook ?: boolean
126134}
127135
128136export default function vitePluginRsc (
129137 rscPluginOptions : RscPluginOptions = { } ,
130138) : Plugin [ ] {
139+ const buildApp : NonNullable < BuilderOptions [ 'buildApp' ] > = async ( builder ) => {
140+ // no-ssr case
141+ // rsc -> client -> rsc -> client
142+ if ( ! builder . environments . ssr ?. config . build . rollupOptions . input ) {
143+ isScanBuild = true
144+ builder . environments . rsc ! . config . build . write = false
145+ builder . environments . client ! . config . build . write = false
146+ await builder . build ( builder . environments . rsc ! )
147+ await builder . build ( builder . environments . client ! )
148+ isScanBuild = false
149+ builder . environments . rsc ! . config . build . write = true
150+ builder . environments . client ! . config . build . write = true
151+ await builder . build ( builder . environments . rsc ! )
152+ // sort for stable build
153+ clientReferenceMetaMap = sortObject ( clientReferenceMetaMap )
154+ serverResourcesMetaMap = sortObject ( serverResourcesMetaMap )
155+ await builder . build ( builder . environments . client ! )
156+
157+ const assetsManifestCode = `export default ${ serializeValueWithRuntime (
158+ buildAssetsManifest ,
159+ ) } `
160+ const manifestPath = path . join (
161+ builder . environments ! . rsc ! . config . build ! . outDir ! ,
162+ BUILD_ASSETS_MANIFEST_NAME ,
163+ )
164+ fs . writeFileSync ( manifestPath , assetsManifestCode )
165+ return
166+ }
167+
168+ // rsc -> ssr -> rsc -> client -> ssr
169+ isScanBuild = true
170+ builder . environments . rsc ! . config . build . write = false
171+ builder . environments . ssr ! . config . build . write = false
172+ await builder . build ( builder . environments . rsc ! )
173+ await builder . build ( builder . environments . ssr ! )
174+ isScanBuild = false
175+ builder . environments . rsc ! . config . build . write = true
176+ builder . environments . ssr ! . config . build . write = true
177+ await builder . build ( builder . environments . rsc ! )
178+ // sort for stable build
179+ clientReferenceMetaMap = sortObject ( clientReferenceMetaMap )
180+ serverResourcesMetaMap = sortObject ( serverResourcesMetaMap )
181+ await builder . build ( builder . environments . client ! )
182+ await builder . build ( builder . environments . ssr ! )
183+ }
184+
131185 return [
132186 {
133187 name : 'rsc' ,
@@ -233,58 +287,14 @@ export default function vitePluginRsc(
233287 } ,
234288 } ,
235289 } ,
236- // TODO: use buildApp hook on v7?
237290 builder : {
238291 sharedPlugins : true ,
239292 sharedConfigBuild : true ,
240- async buildApp ( builder ) {
241- // no-ssr case
242- // rsc -> client -> rsc -> client
243- if ( ! builder . environments . ssr ?. config . build . rollupOptions . input ) {
244- isScanBuild = true
245- builder . environments . rsc ! . config . build . write = false
246- builder . environments . client ! . config . build . write = false
247- await builder . build ( builder . environments . rsc ! )
248- await builder . build ( builder . environments . client ! )
249- isScanBuild = false
250- builder . environments . rsc ! . config . build . write = true
251- builder . environments . client ! . config . build . write = true
252- await builder . build ( builder . environments . rsc ! )
253- // sort for stable build
254- clientReferenceMetaMap = sortObject ( clientReferenceMetaMap )
255- serverResourcesMetaMap = sortObject ( serverResourcesMetaMap )
256- await builder . build ( builder . environments . client ! )
257-
258- const assetsManifestCode = `export default ${ serializeValueWithRuntime (
259- buildAssetsManifest ,
260- ) } `
261- const manifestPath = path . join (
262- builder . environments ! . rsc ! . config . build ! . outDir ! ,
263- BUILD_ASSETS_MANIFEST_NAME ,
264- )
265- fs . writeFileSync ( manifestPath , assetsManifestCode )
266- return
267- }
268-
269- // rsc -> ssr -> rsc -> client -> ssr
270- isScanBuild = true
271- builder . environments . rsc ! . config . build . write = false
272- builder . environments . ssr ! . config . build . write = false
273- await builder . build ( builder . environments . rsc ! )
274- await builder . build ( builder . environments . ssr ! )
275- isScanBuild = false
276- builder . environments . rsc ! . config . build . write = true
277- builder . environments . ssr ! . config . build . write = true
278- await builder . build ( builder . environments . rsc ! )
279- // sort for stable build
280- clientReferenceMetaMap = sortObject ( clientReferenceMetaMap )
281- serverResourcesMetaMap = sortObject ( serverResourcesMetaMap )
282- await builder . build ( builder . environments . client ! )
283- await builder . build ( builder . environments . ssr ! )
284- } ,
293+ buildApp : rscPluginOptions . useBuildAppHook ? undefined : buildApp ,
285294 } ,
286295 }
287296 } ,
297+ buildApp : rscPluginOptions . useBuildAppHook ? buildApp : undefined ,
288298 configResolved ( config_ ) {
289299 config = config_
290300 } ,
@@ -841,7 +851,6 @@ globalThis.AsyncLocalStorage = __viteRscAyncHooks.AsyncLocalStorage;
841851 detectNonOptimizedCjsPlugin ( ) ,
842852 ]
843853}
844-
845854function detectNonOptimizedCjsPlugin ( ) : Plugin {
846855 return {
847856 name : 'rsc:detect-non-optimized-cjs' ,
0 commit comments