151 lines
3.5 KiB
JavaScript
151 lines
3.5 KiB
JavaScript
"use strict";
|
|
|
|
const _ = require(`lodash`);
|
|
|
|
const {
|
|
existsSync
|
|
} = require(`fs`);
|
|
|
|
const queue = require(`async/queue`);
|
|
|
|
const {
|
|
processFile
|
|
} = require(`./process-file`);
|
|
|
|
const {
|
|
createProgress
|
|
} = require(`./utils`);
|
|
|
|
const toProcess = {};
|
|
let totalJobs = 0;
|
|
const q = queue((task, callback) => {
|
|
task(callback);
|
|
}, 1);
|
|
let bar; // when the queue is empty we stop the progressbar
|
|
|
|
q.drain = () => {
|
|
if (bar) {
|
|
bar.done();
|
|
}
|
|
|
|
totalJobs = 0;
|
|
};
|
|
|
|
exports.scheduleJob = async (job, boundActionCreators, pluginOptions, reporter, reportStatus = true) => {
|
|
const inputFileKey = job.inputPath.replace(/\./g, `%2E`);
|
|
const outputFileKey = job.outputPath.replace(/\./g, `%2E`);
|
|
const jobPath = `${inputFileKey}.${outputFileKey}`; // Check if the job has already been queued. If it has, there's nothing
|
|
// to do, return.
|
|
|
|
if (_.has(toProcess, jobPath)) {
|
|
return _.get(toProcess, `${jobPath}.deferred.promise`);
|
|
} // Check if the output file already exists so we don't redo work.
|
|
|
|
|
|
if (existsSync(job.outputPath)) {
|
|
return Promise.resolve(job);
|
|
}
|
|
|
|
let isQueued = false;
|
|
|
|
if (toProcess[inputFileKey]) {
|
|
isQueued = true;
|
|
} // deferred naming comes from https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred
|
|
|
|
|
|
let deferred = {};
|
|
deferred.promise = new Promise((resolve, reject) => {
|
|
deferred.resolve = resolve;
|
|
deferred.reject = reject;
|
|
});
|
|
|
|
if (totalJobs === 0) {
|
|
bar = createProgress(`Generating image thumbnails`, reporter);
|
|
bar.start();
|
|
}
|
|
|
|
totalJobs += 1;
|
|
|
|
_.set(toProcess, jobPath, {
|
|
job: job,
|
|
deferred
|
|
});
|
|
|
|
if (!isQueued) {
|
|
// Create image job
|
|
boundActionCreators.createJob({
|
|
id: `processing image ${job.inputPath}`,
|
|
imagesCount: 1
|
|
}, {
|
|
name: `gatsby-plugin-sharp`
|
|
});
|
|
q.push(cb => {
|
|
runJobs(inputFileKey, boundActionCreators, pluginOptions, reportStatus, cb);
|
|
});
|
|
}
|
|
|
|
return deferred.promise;
|
|
};
|
|
|
|
function runJobs(inputFileKey, boundActionCreators, pluginOptions, reportStatus, cb) {
|
|
const jobs = _.values(toProcess[inputFileKey]);
|
|
|
|
const findDeferred = job => jobs.find(j => j.job === job).deferred;
|
|
|
|
const {
|
|
job
|
|
} = jobs[0]; // Delete the input key from the toProcess list so more jobs can be queued.
|
|
|
|
delete toProcess[inputFileKey]; // Update job info
|
|
|
|
boundActionCreators.setJob({
|
|
id: `processing image ${job.inputPath}`,
|
|
imagesCount: jobs.length
|
|
}, {
|
|
name: `gatsby-plugin-sharp`
|
|
}); // We're now processing the file's jobs.
|
|
|
|
let imagesFinished = 0;
|
|
bar.total = totalJobs;
|
|
|
|
try {
|
|
const promises = processFile(job.inputPath, job.contentDigest, jobs.map(job => job.job), pluginOptions).map(promise => promise.then(job => {
|
|
findDeferred(job).resolve();
|
|
}).catch(err => {
|
|
findDeferred(job).reject({
|
|
err,
|
|
message: `Failed to process image ${job.inputPath}`
|
|
});
|
|
}).then(() => {
|
|
imagesFinished += 1; // only show progress on build
|
|
|
|
if (reportStatus) {
|
|
bar.tick();
|
|
}
|
|
|
|
boundActionCreators.setJob({
|
|
id: `processing image ${job.inputPath}`,
|
|
imagesFinished
|
|
}, {
|
|
name: `gatsby-plugin-sharp`
|
|
});
|
|
}));
|
|
Promise.all(promises).then(() => {
|
|
boundActionCreators.endJob({
|
|
id: `processing image ${job.inputPath}`
|
|
}, {
|
|
name: `gatsby-plugin-sharp`
|
|
});
|
|
cb();
|
|
});
|
|
} catch (err) {
|
|
jobs.forEach(({
|
|
deferred
|
|
}) => {
|
|
deferred.reject({
|
|
err,
|
|
message: err.message
|
|
});
|
|
});
|
|
}
|
|
} |