@@ -17,6 +17,11 @@ import type { Connect, DepOptimizationConfig, InlineConfig, ViteDevServer } from
17
17
import { createAngularMemoryPlugin } from '../../tools/vite/angular-memory-plugin' ;
18
18
import { createAngularLocaleDataPlugin } from '../../tools/vite/i18n-locale-plugin' ;
19
19
import { 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' ;
20
25
import { loadProxyConfiguration , normalizeSourceMaps } from '../../utils' ;
21
26
import { loadEsmModule } from '../../utils/load-esm' ;
22
27
import { Result , ResultFile , ResultKind } from '../application/results' ;
@@ -313,14 +318,25 @@ export async function* serveWithVite(
313
318
? browserOptions . polyfills
314
319
: [ browserOptions . polyfills ] ;
315
320
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
+
316
332
// Setup server and start listening
317
333
const serverConfiguration = await setupServer (
318
334
serverOptions ,
319
335
generatedFiles ,
320
336
assetFiles ,
321
337
browserOptions . preserveSymlinks ,
322
338
externalMetadata ,
323
- ! ! browserOptions . ssr ,
339
+ ssrMode ,
324
340
prebundleTransformer ,
325
341
target ,
326
342
isZonelessApp ( polyfills ) ,
@@ -334,12 +350,6 @@ export async function* serveWithVite(
334
350
server = await createServer ( serverConfiguration ) ;
335
351
await server . listen ( ) ;
336
352
337
- if ( browserOptions . ssr && serverOptions . prebundle !== false ) {
338
- // Warm up the SSR request and begin optimizing dependencies.
339
- // Without this, Vite will only start optimizing SSR modules when the first request is made.
340
- void server . warmupRequest ( './main.server.mjs' , { ssr : true } ) ;
341
- }
342
-
343
353
const urls = server . resolvedUrls ;
344
354
if ( urls && ( urls . local . length || urls . network . length ) ) {
345
355
serverUrl = new URL ( urls . local [ 0 ] ?? urls . network [ 0 ] ) ;
@@ -385,34 +395,37 @@ async function handleUpdate(
385
395
usedComponentStyles : Map < string , string [ ] > ,
386
396
) : Promise < void > {
387
397
const updatedFiles : string [ ] = [ ] ;
388
- let isServerFileUpdated = false ;
398
+ let destroyAngularServerAppCalled = false ;
389
399
390
400
// 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 ;
401
+ for ( const [ file , { updated , type } ] of generatedFiles ) {
402
+ if ( ! updated ) {
403
+ continue ;
404
+ }
395
405
396
- const updatedModules = server . moduleGraph . getModulesByFile (
397
- normalizePath ( join ( server . config . root , file ) ) ,
398
- ) ;
399
- updatedModules ?. forEach ( ( m ) => server ?. moduleGraph . invalidateModule ( m ) ) ;
406
+ if ( type === BuildOutputFileType . ServerApplication && ! destroyAngularServerAppCalled ) {
407
+ // Clear the server app cache
408
+ // This must be done before module invalidation.
409
+ const { ɵdestroyAngularServerApp } = ( await server . ssrLoadModule ( '/main.server.mjs' ) ) as {
410
+ ɵdestroyAngularServerApp : typeof destroyAngularServerApp ;
411
+ } ;
412
+
413
+ ɵdestroyAngularServerApp ( ) ;
414
+ destroyAngularServerAppCalled = true ;
400
415
}
416
+
417
+ updatedFiles . push ( file ) ;
418
+
419
+ const updatedModules = server . moduleGraph . getModulesByFile (
420
+ normalizePath ( join ( server . config . root , file ) ) ,
421
+ ) ;
422
+ updatedModules ?. forEach ( ( m ) => server . moduleGraph . invalidateModule ( m ) ) ;
401
423
}
402
424
403
425
if ( ! updatedFiles . length ) {
404
426
return ;
405
427
}
406
428
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
-
416
429
if ( serverOptions . liveReload || serverOptions . hmr ) {
417
430
if ( updatedFiles . every ( ( f ) => f . endsWith ( '.css' ) ) ) {
418
431
const timestamp = Date . now ( ) ;
@@ -534,7 +547,7 @@ export async function setupServer(
534
547
assets : Map < string , string > ,
535
548
preserveSymlinks : boolean | undefined ,
536
549
externalMetadata : DevServerExternalResultMetadata ,
537
- ssr : boolean ,
550
+ ssrMode : ServerSsrMode ,
538
551
prebundleTransformer : JavaScriptTransformer ,
539
552
target : string [ ] ,
540
553
zoneless : boolean ,
@@ -587,6 +600,9 @@ export async function setupServer(
587
600
preserveSymlinks,
588
601
} ,
589
602
server : {
603
+ warmup : {
604
+ ssrFiles : [ './main.server.mjs' , './server.mjs' ] ,
605
+ } ,
590
606
port : serverOptions . port ,
591
607
strictPort : true ,
592
608
host : serverOptions . host ,
@@ -637,19 +653,21 @@ export async function setupServer(
637
653
} ,
638
654
plugins : [
639
655
createAngularLocaleDataPlugin ( ) ,
640
- createAngularMemoryPlugin ( {
641
- workspaceRoot : serverOptions . workspaceRoot ,
642
- virtualProjectRoot,
656
+ createAngularSetupMiddlewaresPlugin ( {
643
657
outputFiles,
644
658
assets,
645
- ssr,
646
- external : externalMetadata . explicitBrowser ,
647
659
indexHtmlTransformer,
648
660
extensionMiddleware,
649
- normalizePath,
650
661
usedComponentStyles,
662
+ ssrMode,
651
663
} ) ,
652
664
createRemoveIdPrefixPlugin ( externalMetadata . explicitBrowser ) ,
665
+ await createAngularSsrServerPlugin ( serverOptions . workspaceRoot ) ,
666
+ await createAngularMemoryPlugin ( {
667
+ virtualProjectRoot,
668
+ outputFiles,
669
+ external : externalMetadata . explicitBrowser ,
670
+ } ) ,
653
671
] ,
654
672
// Browser only optimizeDeps. (This does not run for SSR dependencies).
655
673
optimizeDeps : getDepOptimizationConfig ( {
0 commit comments