@@ -59,6 +59,10 @@ export class MemoryFiles {
59
59
export class FullBundleDevEnvironment extends DevEnvironment {
60
60
private devEngine ! : DevEngine
61
61
private invalidateCalledModules = new Set < string > ( )
62
+ private debouncedFullReload = debounce ( 20 , ( ) => {
63
+ this . hot . send ( { type : 'full-reload' , path : '*' } )
64
+ this . logger . info ( colors . green ( `page reload` ) , { timestamp : true } )
65
+ } )
62
66
63
67
memoryFiles = new MemoryFiles ( )
64
68
@@ -96,12 +100,15 @@ export class FullBundleDevEnvironment extends DevEnvironment {
96
100
97
101
this . devEngine = await dev ( rollupOptions , outputOptions , {
98
102
onHmrUpdates : ( updates , files ) => {
99
- this . invalidateCalledModules . clear ( )
103
+ if ( files . length === 0 ) {
104
+ return
105
+ }
100
106
// TODO: how to handle errors?
101
107
if ( updates . every ( ( update ) => update . type === 'Noop' ) ) {
102
108
debug ?.( `ignored file change for ${ files . join ( ', ' ) } ` )
103
109
return
104
110
}
111
+ this . invalidateCalledModules . clear ( )
105
112
for ( const update of updates ) {
106
113
this . handleHmrOutput ( files , update )
107
114
}
@@ -126,9 +133,10 @@ export class FullBundleDevEnvironment extends DevEnvironment {
126
133
}
127
134
128
135
private async waitForInitialBuildFinish ( ) : Promise < void > {
136
+ await this . devEngine . ensureCurrentBuildFinish ( )
129
137
while ( this . memoryFiles . size === 0 ) {
130
- await this . devEngine . ensureCurrentBuildFinish ( )
131
138
await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) )
139
+ await this . devEngine . ensureCurrentBuildFinish ( )
132
140
}
133
141
}
134
142
@@ -144,12 +152,14 @@ export class FullBundleDevEnvironment extends DevEnvironment {
144
152
; ( async ( ) => {
145
153
if ( this . invalidateCalledModules . has ( m . path ) ) {
146
154
debug ?.(
147
- ' INVALIDATE: invalidate received, but ignored because it was already invalidated' ,
155
+ ` INVALIDATE: invalidate received from ${ m . path } , but ignored because it was already invalidated` ,
148
156
)
149
157
return
150
158
}
151
159
152
- debug ?.( 'INVALIDATE: invalidate received, re-triggering HMR' )
160
+ debug ?.(
161
+ `INVALIDATE: invalidate received from ${ m . path } , re-triggering HMR` ,
162
+ )
153
163
this . invalidateCalledModules . add ( m . path )
154
164
155
165
// TODO: how to handle errors?
@@ -168,16 +178,18 @@ export class FullBundleDevEnvironment extends DevEnvironment {
168
178
}
169
179
170
180
// TODO: need to check if this is enough
171
- this . handleHmrOutput ( [ m . path ] , update , m . firstInvalidatedBy )
181
+ this . handleHmrOutput ( [ m . path ] , update , {
182
+ firstInvalidatedBy : m . firstInvalidatedBy ,
183
+ reason : m . message ,
184
+ } )
172
185
} ) ( )
173
186
}
174
187
175
188
async triggerBundleRegenerationIfStale ( ) : Promise < boolean > {
176
189
const scheduled = await this . devEngine . scheduleBuildIfStale ( )
177
190
if ( scheduled === 'scheduled' ) {
178
191
this . devEngine . ensureCurrentBuildFinish ( ) . then ( ( ) => {
179
- this . hot . send ( { type : 'full-reload' , path : '*' } )
180
- this . logger . info ( colors . green ( `page reload` ) , { timestamp : true } )
192
+ this . debouncedFullReload ( )
181
193
} )
182
194
debug ?.( `TRIGGER: access to stale bundle, triggered bundle re-generation` )
183
195
}
@@ -207,13 +219,18 @@ export class FullBundleDevEnvironment extends DevEnvironment {
207
219
rolldownOptions . plugins ,
208
220
{
209
221
name : 'vite:full-bundle-mode:save-output' ,
210
- generateBundle : ( _ , bundle ) => {
211
- // NOTE: don't clear memoryFiles here as incremental build re-uses the files
212
- for ( const outputFile of Object . values ( bundle ) ) {
213
- this . memoryFiles . set ( outputFile . fileName , ( ) =>
214
- outputFile . type === 'chunk' ? outputFile . code : outputFile . source ,
215
- )
216
- }
222
+ generateBundle : {
223
+ order : 'post' ,
224
+ handler : ( _ , bundle ) => {
225
+ // NOTE: don't clear memoryFiles here as incremental build re-uses the files
226
+ for ( const outputFile of Object . values ( bundle ) ) {
227
+ this . memoryFiles . set ( outputFile . fileName , ( ) =>
228
+ outputFile . type === 'chunk'
229
+ ? outputFile . code
230
+ : outputFile . source ,
231
+ )
232
+ }
233
+ } ,
217
234
} ,
218
235
} ,
219
236
]
@@ -240,24 +257,25 @@ export class FullBundleDevEnvironment extends DevEnvironment {
240
257
private handleHmrOutput (
241
258
files : string [ ] ,
242
259
hmrOutput : HmrOutput ,
243
- firstInvalidatedBy ?: string ,
260
+ invalidateInformation ?: { firstInvalidatedBy : string ; reason ?: string } ,
244
261
) {
245
262
if ( hmrOutput . type === 'Noop' ) return
246
263
247
264
const shortFile = files
248
265
. map ( ( file ) => getShortName ( file , this . config . root ) )
249
266
. join ( ', ' )
250
267
if ( hmrOutput . type === 'FullReload' ) {
251
- const reason = hmrOutput . reason
252
- ? colors . dim ( ` (${ hmrOutput . reason } )` )
253
- : ''
268
+ const reason =
269
+ ( hmrOutput . reason ? colors . dim ( ` (${ hmrOutput . reason } )` ) : '' ) +
270
+ ( invalidateInformation ?. reason
271
+ ? colors . dim ( ` (${ invalidateInformation . reason } )` )
272
+ : '' )
254
273
this . logger . info (
255
274
colors . green ( `trigger page reload ` ) + colors . dim ( shortFile ) + reason ,
256
- { clear : ! firstInvalidatedBy , timestamp : true } ,
275
+ { clear : ! invalidateInformation , timestamp : true } ,
257
276
)
258
277
this . devEngine . ensureLatestBuild ( ) . then ( ( ) => {
259
- this . hot . send ( { type : 'full-reload' , path : '*' } )
260
- this . logger . info ( colors . green ( `page reload` ) , { timestamp : true } )
278
+ this . debouncedFullReload ( )
261
279
} )
262
280
return
263
281
}
@@ -277,7 +295,7 @@ export class FullBundleDevEnvironment extends DevEnvironment {
277
295
url : hmrOutput . filename ,
278
296
path : boundary . boundary ,
279
297
acceptedPath : boundary . acceptedVia ,
280
- firstInvalidatedBy,
298
+ firstInvalidatedBy : invalidateInformation ?. firstInvalidatedBy ,
281
299
timestamp : Date . now ( ) ,
282
300
}
283
301
} )
@@ -288,7 +306,18 @@ export class FullBundleDevEnvironment extends DevEnvironment {
288
306
this . logger . info (
289
307
colors . green ( `hmr update ` ) +
290
308
colors . dim ( [ ...new Set ( updates . map ( ( u ) => u . path ) ) ] . join ( ', ' ) ) ,
291
- { clear : ! firstInvalidatedBy , timestamp : true } ,
309
+ { clear : ! invalidateInformation , timestamp : true } ,
292
310
)
293
311
}
294
312
}
313
+
314
+ function debounce ( time : number , cb : ( ) => void ) {
315
+ let timer : ReturnType < typeof setTimeout > | null
316
+ return ( ) => {
317
+ if ( timer ) {
318
+ clearTimeout ( timer )
319
+ timer = null
320
+ }
321
+ timer = setTimeout ( cb , time )
322
+ }
323
+ }
0 commit comments