@@ -17,6 +17,11 @@ import type { Connect, DepOptimizationConfig, InlineConfig, ViteDevServer } from
1717import { createAngularMemoryPlugin } from '../../tools/vite/angular-memory-plugin' ;
1818import { createAngularLocaleDataPlugin } from '../../tools/vite/i18n-locale-plugin' ;
1919import { createRemoveIdPrefixPlugin } from '../../tools/vite/id-prefix-plugin' ;
20+ import {
21+ ServerSsrMode ,
22+ createAngularSetupMiddlewaresPlugin ,
23+ } from '../../tools/vite/setup-middlewares-plugin' ;
24+ import { createAngularSsrServerPlugin } from '../../tools/vite/ssr-server-plugin' ;
2025import { loadProxyConfiguration , normalizeSourceMaps } from '../../utils' ;
2126import { loadEsmModule } from '../../utils/load-esm' ;
2227import { Result , ResultFile , ResultKind } from '../application/results' ;
@@ -313,14 +318,25 @@ export async function* serveWithVite(
313318 ? browserOptions . polyfills
314319 : [ browserOptions . polyfills ] ;
315320
321+ let ssrMode : ServerSsrMode = ServerSsrMode . NoSsr ;
322+ if (
323+ browserOptions . outputMode &&
324+ typeof browserOptions . ssr === 'object' &&
325+ browserOptions . ssr . entry
326+ ) {
327+ ssrMode = ServerSsrMode . ExternalSsrMiddleware ;
328+ } else if ( browserOptions . server ) {
329+ ssrMode = ServerSsrMode . InternalSsrMiddleware ;
330+ }
331+
316332 // Setup server and start listening
317333 const serverConfiguration = await setupServer (
318334 serverOptions ,
319335 generatedFiles ,
320336 assetFiles ,
321337 browserOptions . preserveSymlinks ,
322338 externalMetadata ,
323- ! ! browserOptions . ssr ,
339+ ssrMode ,
324340 prebundleTransformer ,
325341 target ,
326342 isZonelessApp ( polyfills ) ,
@@ -337,7 +353,10 @@ export async function* serveWithVite(
337353 if ( browserOptions . ssr && serverOptions . prebundle !== false ) {
338354 // Warm up the SSR request and begin optimizing dependencies.
339355 // Without this, Vite will only start optimizing SSR modules when the first request is made.
340- void server . warmupRequest ( './main.server.mjs' , { ssr : true } ) ;
356+ void Promise . allSettled ( [
357+ server . warmupRequest ( './server.mjs' , { ssr : true } ) ,
358+ server . warmupRequest ( './main.server.mjs' , { ssr : true } ) ,
359+ ] ) ;
341360 }
342361
343362 const urls = server . resolvedUrls ;
@@ -385,34 +404,37 @@ async function handleUpdate(
385404 usedComponentStyles : Map < string , string [ ] > ,
386405) : Promise < void > {
387406 const updatedFiles : string [ ] = [ ] ;
388- let isServerFileUpdated = false ;
407+ let destroyAngularServerAppCalled = false ;
389408
390409 // Invalidate any updated files
391- for ( const [ file , record ] of generatedFiles ) {
392- if ( record . updated ) {
393- updatedFiles . push ( file ) ;
394- isServerFileUpdated ||= record . type === BuildOutputFileType . ServerApplication ;
410+ for ( const [ file , { updated , type } ] of generatedFiles ) {
411+ if ( ! updated ) {
412+ continue ;
413+ }
395414
396- const updatedModules = server . moduleGraph . getModulesByFile (
397- normalizePath ( join ( server . config . root , file ) ) ,
398- ) ;
399- updatedModules ?. forEach ( ( m ) => server ?. moduleGraph . invalidateModule ( m ) ) ;
415+ if ( type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
416+ // Clear the server app cache
417+ // This must be done before module invalidation.
418+ const { ɵdestroyAngularServerApp } = ( await server . ssrLoadModule ( '/main.server.mjs' ) ) as {
419+ ɵdestroyAngularServerApp : typeof destroyAngularServerApp ;
420+ } ;
421+
422+ ɵdestroyAngularServerApp ( ) ;
423+ destroyAngularServerAppCalled = true ;
400424 }
425+
426+ updatedFiles . push ( file ) ;
427+
428+ const updatedModules = server . moduleGraph . getModulesByFile (
429+ normalizePath ( join ( server . config . root , file ) ) ,
430+ ) ;
431+ updatedModules ?. forEach ( ( m ) => server . moduleGraph . invalidateModule ( m ) ) ;
401432 }
402433
403434 if ( ! updatedFiles . length ) {
404435 return ;
405436 }
406437
407- // clean server apps cache
408- if ( isServerFileUpdated ) {
409- const { ɵdestroyAngularServerApp } = ( await server . ssrLoadModule ( '/main.server.mjs' ) ) as {
410- ɵdestroyAngularServerApp : typeof destroyAngularServerApp ;
411- } ;
412-
413- ɵdestroyAngularServerApp ( ) ;
414- }
415-
416438 if ( serverOptions . liveReload || serverOptions . hmr ) {
417439 if ( updatedFiles . every ( ( f ) => f . endsWith ( '.css' ) ) ) {
418440 const timestamp = Date . now ( ) ;
@@ -534,7 +556,7 @@ export async function setupServer(
534556 assets : Map < string , string > ,
535557 preserveSymlinks : boolean | undefined ,
536558 externalMetadata : DevServerExternalResultMetadata ,
537- ssr : boolean ,
559+ ssrMode : ServerSsrMode ,
538560 prebundleTransformer : JavaScriptTransformer ,
539561 target : string [ ] ,
540562 zoneless : boolean ,
@@ -571,6 +593,25 @@ export async function setupServer(
571593 css : {
572594 devSourcemap : true ,
573595 } ,
596+ plugins : [
597+ createAngularLocaleDataPlugin ( ) ,
598+ createAngularSetupMiddlewaresPlugin ( {
599+ outputFiles,
600+ assets,
601+ indexHtmlTransformer,
602+ extensionMiddleware,
603+ usedComponentStyles,
604+ ssrMode,
605+ } ) ,
606+ createRemoveIdPrefixPlugin ( externalMetadata . explicitBrowser ) ,
607+ await createAngularSsrServerPlugin ( serverOptions . workspaceRoot ) ,
608+ await createAngularMemoryPlugin ( {
609+ workspaceRoot : serverOptions . workspaceRoot ,
610+ virtualProjectRoot,
611+ outputFiles,
612+ external : externalMetadata . explicitBrowser ,
613+ } ) ,
614+ ] ,
574615 // Ensure custom 'file' loader build option entries are handled by Vite in application code that
575616 // reference third-party libraries. Relative usage is handled directly by the build and not Vite.
576617 // Only 'file' loader entries are currently supported directly by Vite.
@@ -635,22 +676,6 @@ export async function setupServer(
635676 thirdPartySourcemaps,
636677 } ) ,
637678 } ,
638- plugins : [
639- createAngularLocaleDataPlugin ( ) ,
640- createAngularMemoryPlugin ( {
641- workspaceRoot : serverOptions . workspaceRoot ,
642- virtualProjectRoot,
643- outputFiles,
644- assets,
645- ssr,
646- external : externalMetadata . explicitBrowser ,
647- indexHtmlTransformer,
648- extensionMiddleware,
649- normalizePath,
650- usedComponentStyles,
651- } ) ,
652- createRemoveIdPrefixPlugin ( externalMetadata . explicitBrowser ) ,
653- ] ,
654679 // Browser only optimizeDeps. (This does not run for SSR dependencies).
655680 optimizeDeps : getDepOptimizationConfig ( {
656681 // Only enable with caching since it causes prebundle dependencies to be cached
0 commit comments