Skip to content

Commit 498fbbf

Browse files
authored
feat(gatsby-plugin-sharp): run a single transformation for lazy images (#28574)
* feat(gatsby-plugin-sharp): run a single transformation for lazy images * address review suggestions * rephrased comment
1 parent 4277b3d commit 498fbbf

File tree

1 file changed

+48
-3
lines changed

1 file changed

+48
-3
lines changed

packages/gatsby-plugin-sharp/src/gatsby-node.js

+48-3
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,60 @@ exports.onCreateDevServer = async ({ app, cache, reporter }) => {
7878
return next()
7979
}
8080

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 })
8491
await cache.cache.del(decodedURI)
8592

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+
86101
return res.sendFile(pathOnDisk)
87102
})
88103
}
89104

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+
90135
// So something is wrong with the reporter, when I do this in preBootstrap,
91136
// the progressbar gets not updated
92137
exports.onPostBootstrap = async ({ reporter, cache, store }) => {

0 commit comments

Comments
 (0)