9
9
import path from 'pathe' ;
10
10
import type { EntryInfo , RstestContext , SourceMapInput } from '../types' ;
11
11
import { isDebug } from '../utils' ;
12
- import { pluginBasic } from './plugins/basic' ;
12
+ import { pluginBasic , RUNTIME_CHUNK_NAME } from './plugins/basic' ;
13
13
import { pluginCSSFilter } from './plugins/css-filter' ;
14
14
import { pluginEntryWatch } from './plugins/entry' ;
15
15
import { pluginExternal } from './plugins/external' ;
@@ -18,7 +18,7 @@ import { pluginInspect } from './plugins/inspect';
18
18
import { pluginMockRuntime } from './plugins/mockRuntime' ;
19
19
import { pluginCacheControl } from './plugins/moduleCacheControl' ;
20
20
21
- type EntryToChunkHashes = {
21
+ type TestEntryToChunkHashes = {
22
22
name : string ;
23
23
/** key is chunk name, value is chunk hash */
24
24
chunks : Record < string , string > ;
@@ -122,96 +122,88 @@ export const prepareRsbuild = async (
122
122
export const calcEntriesToRerun = (
123
123
entries : EntryInfo [ ] ,
124
124
chunks : Rspack . StatsChunk [ ] | undefined ,
125
- buildData : { entryToChunkHashes ?: EntryToChunkHashes } ,
125
+ buildData : { entryToChunkHashes ?: TestEntryToChunkHashes } ,
126
126
) : {
127
127
affectedEntries : EntryInfo [ ] ;
128
128
deletedEntries : string [ ] ;
129
129
} => {
130
- const entryToChunkHashes : EntryToChunkHashes = [ ] ;
130
+ const entryToChunkHashesMap = new Map < string , Record < string , string > > ( ) ;
131
131
132
- for ( const entry of entries || [ ] ) {
133
- for ( const chunkName of entry . chunks || [ ] ) {
134
- // Treat runtime chunk as invariant, sometimes it will change but we don't care.
135
- if ( chunkName === 'runtime' ) {
136
- continue ;
137
- }
132
+ // Build current chunk hashes map
133
+ const buildChunkHashes = ( entry : EntryInfo ) => {
134
+ const validChunks = ( entry . chunks || [ ] ) . filter (
135
+ ( chunk ) => chunk !== RUNTIME_CHUNK_NAME ,
136
+ ) ;
138
137
139
- const chunkInfo = chunks ! . find ( ( c ) =>
138
+ validChunks . forEach ( ( chunkName ) => {
139
+ const chunkInfo = chunks ?. find ( ( c ) =>
140
140
c . names ?. includes ( chunkName as string ) ,
141
141
) ;
142
142
if ( chunkInfo ) {
143
- const current = entryToChunkHashes . find (
144
- ( e ) => e . name === entry . testPath ,
145
- ) ;
146
- if ( current ) {
147
- current . chunks [ chunkName ] = chunkInfo . hash ?? '' ;
148
- } else {
149
- entryToChunkHashes . push ( {
150
- name : entry . testPath ,
151
- chunks : {
152
- [ chunkName ] : chunkInfo . hash ?? '' ,
153
- } ,
154
- } ) ;
155
- }
143
+ const existing = entryToChunkHashesMap . get ( entry . testPath ) || { } ;
144
+ existing [ chunkName ] = chunkInfo . hash ?? '' ;
145
+ entryToChunkHashesMap . set ( entry . testPath , existing ) ;
156
146
}
157
- }
158
- }
147
+ } ) ;
148
+ } ;
149
+
150
+ ( entries || [ ] ) . forEach ( buildChunkHashes ) ;
151
+
152
+ const entryToChunkHashes : TestEntryToChunkHashes = Array . from (
153
+ entryToChunkHashesMap . entries ( ) ,
154
+ ) . map ( ( [ name , chunks ] ) => ( { name, chunks } ) ) ;
155
+
156
+ // Process changes if we have previous data
157
+ const affectedTestPaths = new Set < string > ( ) ;
158
+ const deletedEntries : string [ ] = [ ] ;
159
159
160
- let affectedEntries : EntryInfo [ ] = [ ] ;
161
- let deletedEntries : string [ ] = [ ] ;
162
160
if ( buildData . entryToChunkHashes ) {
163
- const prev = buildData . entryToChunkHashes ;
164
- const deleted = prev ?. filter (
165
- ( p ) => ! entryToChunkHashes . find ( ( e ) => e . name === p . name ) ,
161
+ const prevMap = new Map (
162
+ buildData . entryToChunkHashes . map ( ( e ) => [ e . name , e . chunks ] ) ,
166
163
) ;
164
+ const currentNames = new Set ( entryToChunkHashesMap . keys ( ) ) ;
167
165
168
- // deleted
169
- if ( deleted . length ) {
170
- deletedEntries = deleted . map ( ( entry ) => entry . name ) ;
171
- }
166
+ // Find deleted entries
167
+ deletedEntries . push (
168
+ ... Array . from ( prevMap . keys ( ) ) . filter ( ( name ) => ! currentNames . has ( name ) ) ,
169
+ ) ;
172
170
173
- entryToChunkHashes . forEach ( ( entryToChunk ) => {
174
- const prevChunk = prev ?. find ( ( p ) => p . name === entryToChunk . name ) ;
175
- Object . entries ( entryToChunk . chunks ) . forEach ( ( [ chunkName , chunkHash ] ) => {
176
- // modified
177
- if ( prevChunk ) {
178
- const prevHash = prevChunk . chunks [ chunkName ] ;
179
- if ( prevHash !== chunkHash ) {
180
- const entryInfo = entries . find (
181
- ( e ) => e . testPath === entryToChunk . name ,
182
- ) ;
183
- if ( entryInfo ) {
184
- affectedEntries ??= [ ] ;
185
- affectedEntries . push ( entryInfo ) ;
186
- }
187
- }
188
- } else {
189
- // added
190
- const entryInfo = entries . find (
191
- ( e ) => e . testPath === entryToChunk . name ,
192
- ) ;
193
- if ( entryInfo ) {
194
- affectedEntries ??= [ ] ;
195
- affectedEntries . push ( entryInfo ) ;
196
- }
197
- }
198
- } ) ;
171
+ // Find modified or added entries
172
+ const findAffectedEntry = ( testPath : string ) => {
173
+ const currentChunks = entryToChunkHashesMap . get ( testPath ) ;
174
+ const prevChunks = prevMap . get ( testPath ) ;
175
+
176
+ if ( ! currentChunks ) return ;
177
+
178
+ if ( ! prevChunks ) {
179
+ // New entry
180
+ affectedTestPaths . add ( testPath ) ;
181
+ return ;
182
+ }
183
+
184
+ // Check for modified chunks
185
+ const hasChanges = Object . entries ( currentChunks ) . some (
186
+ ( [ chunkName , hash ] ) => prevChunks [ chunkName ] !== hash ,
187
+ ) ;
188
+
189
+ if ( hasChanges ) {
190
+ affectedTestPaths . add ( testPath ) ;
191
+ }
192
+ } ;
193
+
194
+ entryToChunkHashesMap . forEach ( ( _ , testPath ) => {
195
+ findAffectedEntry ( testPath ) ;
199
196
} ) ;
200
197
}
201
198
202
199
buildData . entryToChunkHashes = entryToChunkHashes ;
203
- let dedupeAffectedEntries : EntryInfo [ ] = [ ] ;
204
200
205
- if ( affectedEntries ) {
206
- dedupeAffectedEntries = [ ] ;
207
- for ( const entry of affectedEntries ) {
208
- if ( ! dedupeAffectedEntries . some ( ( e ) => e . testPath === entry . testPath ) ) {
209
- dedupeAffectedEntries . push ( entry ) ;
210
- }
211
- }
212
- }
201
+ // Convert affected test paths to EntryInfo objects
202
+ const affectedEntries = Array . from ( affectedTestPaths )
203
+ . map ( ( testPath ) => entries . find ( ( e ) => e . testPath === testPath ) )
204
+ . filter ( ( entry ) : entry is EntryInfo => entry !== undefined ) ;
213
205
214
- return { affectedEntries : dedupeAffectedEntries , deletedEntries } ;
206
+ return { affectedEntries, deletedEntries } ;
215
207
} ;
216
208
217
209
export const createRsbuildServer = async ( {
@@ -244,6 +236,7 @@ export const createRsbuildServer = async ({
244
236
} > => {
245
237
// Read files from memory via `rspackCompiler.outputFileSystem`
246
238
let rspackCompiler : Rspack . Compiler | Rspack . MultiCompiler | undefined ;
239
+ let isFirstCompile = false ;
247
240
248
241
const rstestCompilerPlugin : RsbuildPlugin = {
249
242
name : 'rstest:compiler' ,
@@ -252,6 +245,10 @@ export const createRsbuildServer = async ({
252
245
// outputFileSystem to be updated later by `rsbuild-dev-middleware`
253
246
rspackCompiler = compiler ;
254
247
} ) ;
248
+
249
+ api . onAfterDevCompile ( ( { isFirstCompile : _isFirstCompile } ) => {
250
+ isFirstCompile = _isFirstCompile ;
251
+ } ) ;
255
252
} ,
256
253
} ;
257
254
@@ -286,13 +283,11 @@ export const createRsbuildServer = async ({
286
283
) ;
287
284
}
288
285
289
- let runCount = 0 ;
290
- const buildData : { entryToChunkHashes ?: EntryToChunkHashes } = { } ;
286
+ const buildData : { entryToChunkHashes ?: TestEntryToChunkHashes } = { } ;
291
287
292
288
const getRsbuildStats = async ( {
293
289
fileFilters,
294
290
} : { fileFilters ?: string [ ] } | undefined = { } ) => {
295
- runCount ++ ;
296
291
const stats = await devServer . environments [ name ] ! . getStats ( ) ;
297
292
298
293
const manifest = devServer . environments [ name ] ! . context
@@ -316,9 +311,6 @@ export const createRsbuildServer = async ({
316
311
// get the compilation time
317
312
chunks : true ,
318
313
timings : true ,
319
- modules : true ,
320
- reasons : true ,
321
- chunkModules : true ,
322
314
} ) ;
323
315
324
316
const readFile = async ( fileName : string ) => {
@@ -418,7 +410,7 @@ export const createRsbuildServer = async ({
418
410
return {
419
411
affectedEntries,
420
412
deletedEntries,
421
- isFirstRun : runCount === 1 ,
413
+ isFirstRun : isFirstCompile ,
422
414
hash,
423
415
entries,
424
416
setupEntries,
0 commit comments