@@ -15,11 +15,11 @@ import assert from 'node:assert';
15
15
import { randomUUID } from 'node:crypto' ;
16
16
import { readFile } from 'node:fs/promises' ;
17
17
import { ServerResponse } from 'node:http' ;
18
- import type { AddressInfo } from 'node:net' ;
19
18
import path from 'node:path' ;
20
- import type { Connect , InlineConfig , ViteDevServer } from 'vite' ;
19
+ import type { Connect , DepOptimizationConfig , InlineConfig , ViteDevServer } from 'vite' ;
21
20
import { BuildOutputFile , BuildOutputFileType } from '../../tools/esbuild/bundler-context' ;
22
21
import { JavaScriptTransformer } from '../../tools/esbuild/javascript-transformer' ;
22
+ import { createRxjsEsmResolutionPlugin } from '../../tools/esbuild/rxjs-esm-resolution-plugin' ;
23
23
import { getFeatureSupport , transformSupportedBrowsersToTargets } from '../../tools/esbuild/utils' ;
24
24
import { createAngularLocaleDataPlugin } from '../../tools/vite/i18n-locale-plugin' ;
25
25
import { renderPage } from '../../utils/server-rendering/render-page' ;
@@ -173,6 +173,8 @@ export async function* serveWithVite(
173
173
174
174
// To avoid disconnecting the array objects from the option, these arrays need to be mutated
175
175
// instead of replaced.
176
+ // TODO: split explicit imports by platform to avoid having Vite optimize server-only/browser-only
177
+ // dependencies twice when SSR is enabled.
176
178
if ( result . externalMetadata ) {
177
179
if ( result . externalMetadata . explicit ) {
178
180
externalMetadata . explicit . push ( ...result . externalMetadata . explicit ) ;
@@ -379,6 +381,8 @@ export async function setupServer(
379
381
path . join ( serverOptions . workspaceRoot , `.angular/vite-root/${ randomUUID ( ) } /` ) ,
380
382
) ;
381
383
384
+ const { builtinModules } = await import ( 'node:module' ) ;
385
+
382
386
const configuration : InlineConfig = {
383
387
configFile : false ,
384
388
envFile : false ,
@@ -412,8 +416,21 @@ export async function setupServer(
412
416
preTransformRequests : externalMetadata . explicit . length === 0 ,
413
417
} ,
414
418
ssr : {
415
- // Exclude any provided dependencies (currently build defined externals)
416
- external : externalMetadata . explicit ,
419
+ // Note: `true` and `/.*/` have different sematics. When true, the `external` option is ignored.
420
+ noExternal : / .* / ,
421
+ // Exclude any Node.js built in module and provided dependencies (currently build defined externals)
422
+ external : [ ...builtinModules , ...externalMetadata . explicit ] ,
423
+ optimizeDeps : getDepOptimizationConfig ( {
424
+ // Only enable with caching since it causes prebundle dependencies to be cached
425
+ disabled : ! serverOptions . cacheOptions . enabled ,
426
+ // Exclude any explicitly defined dependencies (currently build defined externals)
427
+ exclude : externalMetadata . explicit ,
428
+ // Include all implict dependencies from the external packages internal option
429
+ include : externalMetadata . implicit ,
430
+ ssr : true ,
431
+ prebundleTransformer,
432
+ target,
433
+ } ) ,
417
434
} ,
418
435
plugins : [
419
436
createAngularLocaleDataPlugin ( ) ,
@@ -645,35 +662,18 @@ export async function setupServer(
645
662
} ,
646
663
} ,
647
664
] ,
648
- optimizeDeps : {
665
+ // Browser only optimizeDeps. (This does not run for SSR dependencies).
666
+ optimizeDeps : getDepOptimizationConfig ( {
649
667
// Only enable with caching since it causes prebundle dependencies to be cached
650
668
disabled : ! serverOptions . cacheOptions . enabled ,
651
669
// Exclude any explicitly defined dependencies (currently build defined externals)
652
670
exclude : externalMetadata . explicit ,
653
671
// Include all implict dependencies from the external packages internal option
654
672
include : externalMetadata . implicit ,
655
- // Skip automatic file-based entry point discovery
656
- entries : [ ] ,
657
- // Add an esbuild plugin to run the Angular linker on dependencies
658
- esbuildOptions : {
659
- // Set esbuild supported targets.
660
- target,
661
- supported : getFeatureSupport ( target ) ,
662
- plugins : [
663
- {
664
- name : 'angular-vite-optimize-deps' ,
665
- setup ( build ) {
666
- build . onLoad ( { filter : / \. [ c m ] ? j s $ / } , async ( args ) => {
667
- return {
668
- contents : await prebundleTransformer . transformFile ( args . path ) ,
669
- loader : 'js' ,
670
- } ;
671
- } ) ;
672
- } ,
673
- } ,
674
- ] ,
675
- } ,
676
- } ,
673
+ ssr : false ,
674
+ prebundleTransformer,
675
+ target,
676
+ } ) ,
677
677
} ;
678
678
679
679
if ( serverOptions . ssl ) {
@@ -728,3 +728,57 @@ function pathnameWithoutServePath(url: string, serverOptions: NormalizedDevServe
728
728
729
729
return pathname ;
730
730
}
731
+
732
+ type ViteEsBuildPlugin = NonNullable <
733
+ NonNullable < DepOptimizationConfig [ 'esbuildOptions' ] > [ 'plugins' ]
734
+ > [ 0 ] ;
735
+
736
+ function getDepOptimizationConfig ( {
737
+ disabled,
738
+ exclude,
739
+ include,
740
+ target,
741
+ prebundleTransformer,
742
+ ssr,
743
+ } : {
744
+ disabled : boolean ;
745
+ exclude : string [ ] ;
746
+ include : string [ ] ;
747
+ target : string [ ] ;
748
+ prebundleTransformer : JavaScriptTransformer ;
749
+ ssr : boolean ;
750
+ } ) : DepOptimizationConfig {
751
+ const plugins : ViteEsBuildPlugin [ ] = [
752
+ {
753
+ name : `angular-vite-optimize-deps${ ssr ? '-ssr' : '' } ` ,
754
+ setup ( build ) {
755
+ build . onLoad ( { filter : / \. [ c m ] ? j s $ / } , async ( args ) => {
756
+ return {
757
+ contents : await prebundleTransformer . transformFile ( args . path ) ,
758
+ loader : 'js' ,
759
+ } ;
760
+ } ) ;
761
+ } ,
762
+ } ,
763
+ ] ;
764
+
765
+ if ( ssr ) {
766
+ plugins . unshift ( createRxjsEsmResolutionPlugin ( ) as ViteEsBuildPlugin ) ;
767
+ }
768
+
769
+ return {
770
+ // Only enable with caching since it causes prebundle dependencies to be cached
771
+ disabled,
772
+ // Exclude any explicitly defined dependencies (currently build defined externals)
773
+ exclude,
774
+ // Include all implict dependencies from the external packages internal option
775
+ include,
776
+ // Add an esbuild plugin to run the Angular linker on dependencies
777
+ esbuildOptions : {
778
+ // Set esbuild supported targets.
779
+ target,
780
+ supported : getFeatureSupport ( target ) ,
781
+ plugins,
782
+ } ,
783
+ } ;
784
+ }
0 commit comments