@@ -78,15 +78,60 @@ exports.onCreateDevServer = async ({ app, cache, reporter }) => {
78
78
return next ( )
79
79
}
80
80
81
- await _unstable_createJob ( cacheResult , { reporter } )
82
- // we should implement cache.del inside our abstraction
83
- await cache . cache . del ( jobContentDigest )
81
+ // We are going to run a job for a single operation only
82
+ // and postpone all other operations
83
+ // This speeds up the loading of lazy images in the browser and
84
+ // also helps to free up the browser connection queue earlier.
85
+ const {
86
+ matchingJob,
87
+ jobWithRemainingOperations,
88
+ } = splitOperationsByRequestedFile ( cacheResult , pathOnDisk )
89
+
90
+ await _unstable_createJob ( matchingJob , { reporter } )
84
91
await cache . cache . del ( decodedURI )
85
92
93
+ if ( jobWithRemainingOperations . args . operations . length > 0 ) {
94
+ // There are still some operations pending for this job - replace the cached job
95
+ await cache . cache . set ( jobContentDigest , jobWithRemainingOperations )
96
+ } else {
97
+ // No operations left to process - purge the cache
98
+ await cache . cache . del ( jobContentDigest )
99
+ }
100
+
86
101
return res . sendFile ( pathOnDisk )
87
102
} )
88
103
}
89
104
105
+ // Split the job into two jobs:
106
+ // - first job with a single operation matching requestedPathOnDisk
107
+ // - second job with all other operations
108
+ // so the two resulting jobs are only different by their operations
109
+ function splitOperationsByRequestedFile ( job , requestedPathOnDisk ) {
110
+ const matchingJob = {
111
+ ...job ,
112
+ args : { ...job . args , operations : [ ] } ,
113
+ }
114
+ const jobWithRemainingOperations = {
115
+ ...job ,
116
+ args : { ...job . args , operations : [ ] } ,
117
+ }
118
+
119
+ job . args . operations . forEach ( op => {
120
+ const operationPath = path . resolve ( path . join ( job . outputDir , op . outputPath ) )
121
+ if ( operationPath === requestedPathOnDisk ) {
122
+ matchingJob . args . operations . push ( op )
123
+ } else {
124
+ jobWithRemainingOperations . args . operations . push ( op )
125
+ }
126
+ } )
127
+ if ( matchingJob . args . operations . length === 0 ) {
128
+ throw new Error (
129
+ `Could not find matching operation for ${ requestedPathOnDisk } `
130
+ )
131
+ }
132
+ return { matchingJob, jobWithRemainingOperations }
133
+ }
134
+
90
135
// So something is wrong with the reporter, when I do this in preBootstrap,
91
136
// the progressbar gets not updated
92
137
exports . onPostBootstrap = async ( { reporter, cache, store } ) => {
0 commit comments