88
99import type { BuilderContext } from '@angular-devkit/architect' ;
1010import type { json } from '@angular-devkit/core' ;
11+ import type { OutputFile } from 'esbuild' ;
1112import { lookup as lookupMimeType } from 'mrmime' ;
1213import assert from 'node:assert' ;
1314import { BinaryLike , createHash } from 'node:crypto' ;
@@ -55,71 +56,25 @@ export async function* serveWithVite(
5556
5657 let server : ViteDevServer | undefined ;
5758 let listeningAddress : AddressInfo | undefined ;
58- const outputFiles = new Map < string , OutputFileRecord > ( ) ;
59- const assets = new Map < string , string > ( ) ;
59+ const generatedFiles = new Map < string , OutputFileRecord > ( ) ;
60+ const assetFiles = new Map < string , string > ( ) ;
6061 // TODO: Switch this to an architect schedule call when infrastructure settings are supported
6162 for await ( const result of buildEsbuildBrowser ( browserOptions , context , { write : false } ) ) {
6263 assert ( result . outputFiles , 'Builder did not provide result files.' ) ;
6364
6465 // Analyze result files for changes
65- const seen = new Set < string > ( [ '/index.html' ] ) ;
66- for ( const file of result . outputFiles ) {
67- const filePath = '/' + normalizePath ( file . path ) ;
68- seen . add ( filePath ) ;
69-
70- // Skip analysis of sourcemaps
71- if ( filePath . endsWith ( '.map' ) ) {
72- outputFiles . set ( filePath , {
73- contents : file . contents ,
74- size : file . contents . byteLength ,
75- updated : false ,
76- } ) ;
77-
78- continue ;
79- }
80-
81- let fileHash : Buffer | undefined ;
82- const existingRecord = outputFiles . get ( filePath ) ;
83- if ( existingRecord && existingRecord . size === file . contents . byteLength ) {
84- // Only hash existing file when needed
85- if ( existingRecord . hash === undefined ) {
86- existingRecord . hash = hashContent ( existingRecord . contents ) ;
87- }
66+ analyzeResultFiles ( result . outputFiles , generatedFiles ) ;
8867
89- // Compare against latest result output
90- fileHash = hashContent ( file . contents ) ;
91- if ( fileHash . equals ( existingRecord . hash ) ) {
92- // Same file
93- existingRecord . updated = false ;
94- continue ;
95- }
96- }
97-
98- outputFiles . set ( filePath , {
99- contents : file . contents ,
100- size : file . contents . byteLength ,
101- hash : fileHash ,
102- updated : true ,
103- } ) ;
104- }
105-
106- // Clear stale output files
107- for ( const file of outputFiles . keys ( ) ) {
108- if ( ! seen . has ( file ) ) {
109- outputFiles . delete ( file ) ;
110- }
111- }
112-
113- assets . clear ( ) ;
68+ assetFiles . clear ( ) ;
11469 if ( result . assetFiles ) {
11570 for ( const asset of result . assetFiles ) {
116- assets . set ( '/' + normalizePath ( asset . destination ) , asset . source ) ;
71+ assetFiles . set ( '/' + normalizePath ( asset . destination ) , asset . source ) ;
11772 }
11873 }
11974
12075 if ( server ) {
12176 // Invalidate any updated files
122- for ( const [ file , record ] of outputFiles ) {
77+ for ( const [ file , record ] of generatedFiles ) {
12378 if ( record . updated ) {
12479 const updatedModules = server . moduleGraph . getModulesByFile ( file ) ;
12580 updatedModules ?. forEach ( ( m ) => server ?. moduleGraph . invalidateModule ( m ) ) ;
@@ -137,7 +92,8 @@ export async function* serveWithVite(
13792 }
13893 } else {
13994 // Setup server and start listening
140- server = await setupServer ( serverOptions , outputFiles , assets ) ;
95+ const serverConfiguration = await setupServer ( serverOptions , generatedFiles , assetFiles ) ;
96+ server = await createServer ( serverConfiguration ) ;
14197
14298 await server . listen ( ) ;
14399 listeningAddress = server . httpServer ?. address ( ) as AddressInfo ;
@@ -160,11 +116,64 @@ export async function* serveWithVite(
160116 }
161117}
162118
163- async function setupServer (
119+ function analyzeResultFiles (
120+ resultFiles : OutputFile [ ] ,
121+ generatedFiles : Map < string , OutputFileRecord > ,
122+ ) {
123+ const seen = new Set < string > ( [ '/index.html' ] ) ;
124+ for ( const file of resultFiles ) {
125+ const filePath = '/' + normalizePath ( file . path ) ;
126+ seen . add ( filePath ) ;
127+
128+ // Skip analysis of sourcemaps
129+ if ( filePath . endsWith ( '.map' ) ) {
130+ generatedFiles . set ( filePath , {
131+ contents : file . contents ,
132+ size : file . contents . byteLength ,
133+ updated : false ,
134+ } ) ;
135+
136+ continue ;
137+ }
138+
139+ let fileHash : Buffer | undefined ;
140+ const existingRecord = generatedFiles . get ( filePath ) ;
141+ if ( existingRecord && existingRecord . size === file . contents . byteLength ) {
142+ // Only hash existing file when needed
143+ if ( existingRecord . hash === undefined ) {
144+ existingRecord . hash = hashContent ( existingRecord . contents ) ;
145+ }
146+
147+ // Compare against latest result output
148+ fileHash = hashContent ( file . contents ) ;
149+ if ( fileHash . equals ( existingRecord . hash ) ) {
150+ // Same file
151+ existingRecord . updated = false ;
152+ continue ;
153+ }
154+ }
155+
156+ generatedFiles . set ( filePath , {
157+ contents : file . contents ,
158+ size : file . contents . byteLength ,
159+ hash : fileHash ,
160+ updated : true ,
161+ } ) ;
162+ }
163+
164+ // Clear stale output files
165+ for ( const file of generatedFiles . keys ( ) ) {
166+ if ( ! seen . has ( file ) ) {
167+ generatedFiles . delete ( file ) ;
168+ }
169+ }
170+ }
171+
172+ export async function setupServer (
164173 serverOptions : NormalizedDevServerOptions ,
165174 outputFiles : Map < string , OutputFileRecord > ,
166175 assets : Map < string , string > ,
167- ) : Promise < ViteDevServer > {
176+ ) : Promise < InlineConfig > {
168177 const proxy = await loadProxyConfiguration (
169178 serverOptions . workspaceRoot ,
170179 serverOptions . proxyConfig ,
@@ -330,7 +339,5 @@ async function setupServer(
330339 }
331340 }
332341
333- const server = await createServer ( configuration ) ;
334-
335- return server ;
342+ return configuration ;
336343}
0 commit comments