@@ -96,7 +96,21 @@ export async function startDevServer(
9696
9797 const { host, port, watch, liveReload, fullRender } =
9898 resolveDevServerOptions ( input )
99- let fullBuild : Promise < unknown > | undefined
99+ let setupReady : Promise < void > = Promise . resolve ( )
100+ const activeResponses = new Set < Promise < void > > ( )
101+ const beginSiteRequest = async ( ) => {
102+ while ( true ) {
103+ const ready = setupReady
104+ await ready
105+ if ( ready !== setupReady ) continue
106+ const finished = Promise . withResolvers < void > ( )
107+ activeResponses . add ( finished . promise )
108+ return ( ) => {
109+ activeResponses . delete ( finished . promise )
110+ finished . resolve ( )
111+ }
112+ }
113+ }
100114
101115 const clients : LiveReloadClients = new Map ( )
102116 let liveReloadVersion = 0
@@ -169,7 +183,13 @@ export async function startDevServer(
169183 reason : string ,
170184 options ?: { recreateBuilder ?: boolean ; reloadConfig ?: boolean } ,
171185 ) => {
186+ const previousSetup = setupReady
187+ const prepared = Promise . withResolvers < void > ( )
188+ setupReady = prepared . promise
172189 try {
190+ await previousSetup
191+ // Output cleanup must not race HTML reads or streamed asset responses.
192+ await Promise . all ( [ ...activeResponses ] )
173193 if ( options ?. reloadConfig ) {
174194 buildInput = await projectConfig . load ( baseBuildInput )
175195 watchConfigDependencies ( )
@@ -181,8 +201,7 @@ export async function startDevServer(
181201 devMiddleware = composeDevMiddleware ( buildInput . options ?. plugins ?? [ ] )
182202 }
183203 if ( fullRender && ! initialSetupDone ) {
184- fullBuild = incremental . buildAll ( reason )
185- await fullBuild
204+ await incremental . buildAll ( reason )
186205 }
187206 await incremental . prepareForRequests ( )
188207 if ( ! initialSetupDone ) {
@@ -194,6 +213,8 @@ export async function startDevServer(
194213 notifyReload ( reason )
195214 } catch ( error ) {
196215 logError ( log , error , 'dev setup failed' )
216+ } finally {
217+ prepared . resolve ( )
197218 }
198219 }
199220
@@ -248,9 +269,7 @@ export async function startDevServer(
248269 basePath : config . basePath ,
249270 i18n : config . i18n ,
250271 liveReload,
251- waitForFullBuild : async ( ) => {
252- if ( fullRender ) await fullBuild
253- } ,
272+ beginSiteRequest,
254273 // Config changes replace the builder, so requests ask for the current one.
255274 getIncremental : ( ) => incremental ,
256275 handlePluginRequest : ( req , res ) => devMiddleware ( req , res ) ,
@@ -267,16 +286,6 @@ export async function startDevServer(
267286 } )
268287 server . keepAliveTimeout = 1000
269288 server . headersTimeout = 5000
270- server . listen ( port , host , ( ) => {
271- log . info ( 'dev server listening' , {
272- host,
273- port,
274- outDir : config . outDir ,
275- liveReload,
276- watch,
277- fullRender,
278- } )
279- } )
280289
281290 if ( watch ) {
282291 watcher = await watchTree ( config . contentDir , ( filePath ) => {
@@ -287,6 +296,16 @@ export async function startDevServer(
287296 watchConfigDependencies ( )
288297
289298 void requestRebuild ( )
299+ server . listen ( port , host , ( ) => {
300+ log . info ( 'dev server listening' , {
301+ host,
302+ port,
303+ outDir : config . outDir ,
304+ liveReload,
305+ watch,
306+ fullRender,
307+ } )
308+ } )
290309
291310 const shutdown = async ( ) => {
292311 if ( shuttingDown ) return
@@ -376,7 +395,7 @@ type DevServerRequestHandlerInput = {
376395 basePath : string
377396 i18n : I18nConfig
378397 liveReload : boolean
379- waitForFullBuild : ( ) => Promise < void >
398+ beginSiteRequest : ( ) => Promise < ( ) => void >
380399 getIncremental : ( ) => IncrementalBuilder
381400 /** Resolves true when a plugin's dev middleware responded. */
382401 handlePluginRequest : (
@@ -396,7 +415,7 @@ function createDevServerRequestHandler(input: DevServerRequestHandlerInput) {
396415 basePath,
397416 i18n,
398417 liveReload,
399- waitForFullBuild ,
418+ beginSiteRequest ,
400419 getIncremental,
401420 handlePluginRequest,
402421 clients,
@@ -441,7 +460,13 @@ function createDevServerRequestHandler(input: DevServerRequestHandlerInput) {
441460 let fileResult : Awaited < ReturnType < typeof resolveRequestFile > >
442461 let incremental : IncrementalBuilder
443462 try {
444- await waitForFullBuild ( )
463+ const finishRequest = await beginSiteRequest ( )
464+ if ( res . destroyed ) {
465+ finishRequest ( )
466+ return
467+ }
468+ res . once ( 'finish' , finishRequest )
469+ res . once ( 'close' , finishRequest )
445470 incremental = getIncremental ( )
446471 res . setTimeout ( REQUEST_TIMEOUT_MS , ( ) => {
447472 res . destroy ( )
0 commit comments