88
99import { readFile } from 'node:fs/promises' ;
1010import { join } from 'node:path' ;
11- import type { Connect , InlineConfig } from 'vite' ;
11+ import type { Connect , InlineConfig , SSROptions , ServerOptions } from 'vite' ;
1212import type { ComponentStyleRecord } from '../../../tools/vite/middlewares' ;
1313import {
1414 ServerSsrMode ,
@@ -25,7 +25,116 @@ import { type ApplicationBuilderInternalOptions, JavaScriptTransformer } from '.
2525import type { NormalizedDevServerOptions } from '../options' ;
2626import { DevServerExternalResultMetadata , OutputAssetRecord , OutputFileRecord } from './utils' ;
2727
28- // eslint-disable-next-line max-lines-per-function
28+ async function createServerConfig (
29+ serverOptions : NormalizedDevServerOptions ,
30+ assets : Map < string , OutputAssetRecord > ,
31+ ssrMode : ServerSsrMode ,
32+ preTransformRequests : boolean ,
33+ cacheDir : string ,
34+ ) : Promise < ServerOptions > {
35+ const proxy = await loadProxyConfiguration (
36+ serverOptions . workspaceRoot ,
37+ serverOptions . proxyConfig ,
38+ ) ;
39+
40+ // Files used for SSR warmup.
41+ let ssrFiles : string [ ] | undefined ;
42+ switch ( ssrMode ) {
43+ case ServerSsrMode . InternalSsrMiddleware :
44+ ssrFiles = [ './main.server.mjs' ] ;
45+ break ;
46+ case ServerSsrMode . ExternalSsrMiddleware :
47+ ssrFiles = [ './main.server.mjs' , './server.mjs' ] ;
48+ break ;
49+ }
50+
51+ const server : ServerOptions = {
52+ preTransformRequests,
53+ warmup : {
54+ ssrFiles,
55+ } ,
56+ port : serverOptions . port ,
57+ strictPort : true ,
58+ host : serverOptions . host ,
59+ open : serverOptions . open ,
60+ allowedHosts : serverOptions . allowedHosts ,
61+ headers : serverOptions . headers ,
62+ // Disable the websocket if live reload is disabled (false/undefined are the only valid values)
63+ ws : serverOptions . liveReload === false && serverOptions . hmr === false ? false : undefined ,
64+ // When server-side rendering (SSR) is enabled togather with SSL and Express is being used,
65+ // we must configure Vite to use HTTP/1.1.
66+ // This is necessary because Express does not support HTTP/2.
67+ // We achieve this by defining an empty proxy.
68+ // See: https://github.com/vitejs/vite/blob/c4b532cc900bf988073583511f57bd581755d5e3/packages/vite/src/node/http.ts#L106
69+ proxy :
70+ serverOptions . ssl && ssrMode === ServerSsrMode . ExternalSsrMiddleware ? ( proxy ?? { } ) : proxy ,
71+ cors : {
72+ // This will add the header `Access-Control-Allow-Origin: http://example.com`,
73+ // where `http://example.com` is the requesting origin.
74+ origin : true ,
75+ // Allow preflight requests to be proxied.
76+ preflightContinue : true ,
77+ } ,
78+ // File watching is handled by the build directly. `null` disables file watching for Vite.
79+ watch : null ,
80+ fs : {
81+ // Ensure cache directory, node modules, and all assets are accessible by the client.
82+ // The first two are required for Vite to function in prebundling mode (the default) and to load
83+ // the Vite client-side code for browser reloading. These would be available by default but when
84+ // the `allow` option is explicitly configured, they must be included manually.
85+ allow : [
86+ cacheDir ,
87+ join ( serverOptions . workspaceRoot , 'node_modules' ) ,
88+ ...[ ...assets . values ( ) ] . map ( ( { source } ) => source ) ,
89+ ] ,
90+ } ,
91+ } ;
92+
93+ if ( serverOptions . ssl ) {
94+ if ( serverOptions . sslCert && serverOptions . sslKey ) {
95+ server . https = {
96+ cert : await readFile ( serverOptions . sslCert ) ,
97+ key : await readFile ( serverOptions . sslKey ) ,
98+ } ;
99+ }
100+ }
101+
102+ return server ;
103+ }
104+
105+ function createSsrConfig (
106+ externalMetadata : DevServerExternalResultMetadata ,
107+ serverOptions : NormalizedDevServerOptions ,
108+ prebundleTransformer : JavaScriptTransformer ,
109+ zoneless : boolean ,
110+ target : string [ ] ,
111+ prebundleLoaderExtensions : EsbuildLoaderOption | undefined ,
112+ thirdPartySourcemaps : boolean ,
113+ define : ApplicationBuilderInternalOptions [ 'define' ] ,
114+ ) : SSROptions {
115+ return {
116+ // Note: `true` and `/.*/` have different sematics. When true, the `external` option is ignored.
117+ noExternal : / .* / ,
118+ // Exclude any Node.js built in module and provided dependencies (currently build defined externals)
119+ external : externalMetadata . explicitServer ,
120+ optimizeDeps : getDepOptimizationConfig ( {
121+ // Only enable with caching since it causes prebundle dependencies to be cached
122+ disabled : serverOptions . prebundle === false ,
123+ // Exclude any explicitly defined dependencies (currently build defined externals and node.js built-ins)
124+ exclude : externalMetadata . explicitServer ,
125+ // Include all implict dependencies from the external packages internal option
126+ include : externalMetadata . implicitServer ,
127+ ssr : true ,
128+ prebundleTransformer,
129+ zoneless,
130+ target,
131+ loader : prebundleLoaderExtensions ,
132+ thirdPartySourcemaps,
133+ define,
134+ } ) ,
135+ } ;
136+ }
137+
29138export async function setupServer (
30139 serverOptions : NormalizedDevServerOptions ,
31140 outputFiles : Map < string , OutputFileRecord > ,
@@ -44,11 +153,6 @@ export async function setupServer(
44153 indexHtmlTransformer ?: ( content : string ) => Promise < string > ,
45154 thirdPartySourcemaps = false ,
46155) : Promise < InlineConfig > {
47- const proxy = await loadProxyConfiguration (
48- serverOptions . workspaceRoot ,
49- serverOptions . proxyConfig ,
50- ) ;
51-
52156 // dynamically import Vite for ESM compatibility
53157 const { normalizePath } = await loadEsmModule < typeof import ( 'vite' ) > ( 'vite' ) ;
54158
@@ -57,17 +161,6 @@ export async function setupServer(
57161 join ( serverOptions . workspaceRoot , `.angular/vite-root` , serverOptions . buildTarget . project ) ,
58162 ) ;
59163
60- // Files used for SSR warmup.
61- let ssrFiles : string [ ] | undefined ;
62- switch ( ssrMode ) {
63- case ServerSsrMode . InternalSsrMiddleware :
64- ssrFiles = [ './main.server.mjs' ] ;
65- break ;
66- case ServerSsrMode . ExternalSsrMiddleware :
67- ssrFiles = [ './main.server.mjs' , './server.mjs' ] ;
68- break ;
69- }
70-
71164 /**
72165 * Required when using `externalDependencies` to prevent Vite load errors.
73166 *
@@ -78,6 +171,7 @@ export async function setupServer(
78171 const preTransformRequests =
79172 externalMetadata . explicitBrowser . length === 0 && ssrMode === ServerSsrMode . NoSsr ;
80173 const cacheDir = join ( serverOptions . cacheOptions . path , serverOptions . buildTarget . project , 'vite' ) ;
174+
81175 const configuration : InlineConfig = {
82176 configFile : false ,
83177 envFile : false ,
@@ -109,70 +203,23 @@ export async function setupServer(
109203 dev : {
110204 preTransformRequests,
111205 } ,
112- server : {
206+ server : await createServerConfig (
207+ serverOptions ,
208+ assets ,
209+ ssrMode ,
113210 preTransformRequests ,
114- warmup : {
115- ssrFiles,
116- } ,
117- port : serverOptions . port ,
118- strictPort : true ,
119- host : serverOptions . host ,
120- open : serverOptions . open ,
121- allowedHosts : serverOptions . allowedHosts ,
122- headers : serverOptions . headers ,
123- // Disable the websocket if live reload is disabled (false/undefined are the only valid values)
124- ws : serverOptions . liveReload === false && serverOptions . hmr === false ? false : undefined ,
125- // When server-side rendering (SSR) is enabled togather with SSL and Express is being used,
126- // we must configure Vite to use HTTP/1.1.
127- // This is necessary because Express does not support HTTP/2.
128- // We achieve this by defining an empty proxy.
129- // See: https://github.com/vitejs/vite/blob/c4b532cc900bf988073583511f57bd581755d5e3/packages/vite/src/node/http.ts#L106
130- proxy :
131- serverOptions . ssl && ssrMode === ServerSsrMode . ExternalSsrMiddleware
132- ? ( proxy ?? { } )
133- : proxy ,
134- cors : {
135- // This will add the header `Access-Control-Allow-Origin: http://example.com`,
136- // where `http://example.com` is the requesting origin.
137- origin : true ,
138- // Allow preflight requests to be proxied.
139- preflightContinue : true ,
140- } ,
141- // File watching is handled by the build directly. `null` disables file watching for Vite.
142- watch : null ,
143- fs : {
144- // Ensure cache directory, node modules, and all assets are accessible by the client.
145- // The first two are required for Vite to function in prebundling mode (the default) and to load
146- // the Vite client-side code for browser reloading. These would be available by default but when
147- // the `allow` option is explicitly configured, they must be included manually.
148- allow : [
149- cacheDir ,
150- join ( serverOptions . workspaceRoot , 'node_modules' ) ,
151- ...[ ...assets . values ( ) ] . map ( ( { source } ) => source ) ,
152- ] ,
153- } ,
154- } ,
155- ssr : {
156- // Note: `true` and `/.*/` have different sematics. When true, the `external` option is ignored.
157- noExternal : / .* / ,
158- // Exclude any Node.js built in module and provided dependencies (currently build defined externals)
159- external : externalMetadata . explicitServer ,
160- optimizeDeps : getDepOptimizationConfig ( {
161- // Only enable with caching since it causes prebundle dependencies to be cached
162- disabled : serverOptions . prebundle === false ,
163- // Exclude any explicitly defined dependencies (currently build defined externals and node.js built-ins)
164- exclude : externalMetadata . explicitServer ,
165- // Include all implict dependencies from the external packages internal option
166- include : externalMetadata . implicitServer ,
167- ssr : true ,
168- prebundleTransformer,
169- zoneless,
170- target,
171- loader : prebundleLoaderExtensions ,
172- thirdPartySourcemaps,
173- define,
174- } ) ,
175- } ,
211+ cacheDir ,
212+ ) ,
213+ ssr : createSsrConfig (
214+ externalMetadata ,
215+ serverOptions ,
216+ prebundleTransformer ,
217+ zoneless ,
218+ target ,
219+ prebundleLoaderExtensions ,
220+ thirdPartySourcemaps ,
221+ define ,
222+ ) ,
176223 plugins : [
177224 createAngularLocaleDataPlugin ( ) ,
178225 createAngularSetupMiddlewaresPlugin ( {
@@ -215,14 +262,7 @@ export async function setupServer(
215262 } ;
216263
217264 if ( serverOptions . ssl ) {
218- if ( serverOptions . sslCert && serverOptions . sslKey ) {
219- configuration . server ??= { } ;
220- // server configuration is defined above
221- configuration . server . https = {
222- cert : await readFile ( serverOptions . sslCert ) ,
223- key : await readFile ( serverOptions . sslKey ) ,
224- } ;
225- } else {
265+ if ( ! serverOptions . sslCert || ! serverOptions . sslKey ) {
226266 const { default : basicSslPlugin } = await import ( '@vitejs/plugin-basic-ssl' ) ;
227267 configuration . plugins ??= [ ] ;
228268 configuration . plugins . push ( basicSslPlugin ( ) ) ;
0 commit comments