hard-source-webpack-plugin
Version:
Hard cache the source of modules in webpack.
150 lines (135 loc) • 3.78 kB
JavaScript
// - scan dirs
// - stat items
// - hash files
// - stat dir items under
// - hash files
// - hash files
const crypto = require('crypto');
const fs = require('graceful-fs');
const path = require('path');
const pkgDir = require('pkg-dir');
const promisify = require('./util/promisify');
const readFile = promisify(fs.readFile);
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
function hashFile(file) {
return readFile(file)
.then(src => [
file,
crypto
.createHash('md5')
.update(src)
.digest('hex'),
])
.catch(() => {});
}
function hashObject(obj) {
const hash = crypto.createHash('md5');
obj.forEach(item => {
hash.update(item[0]);
hash.update(item[1]);
});
return hash.digest('hex');
}
function hashFiles(root, files) {
return Promise.all(files.map(file => hashFile(path.join(root, file)))).then(
hashes => hashes.filter(Boolean),
);
}
function flatten(items) {
return (items || []).reduce(
(carry, item) => (item ? carry.concat(item) : carry),
[],
);
}
const inputs = async ({ files, directories, root = process.cwd() } = {}) => {
let defaults;
if (!files && !directories) {
const lockFiles = (await Promise.all(
['package-lock.json', 'yarn.lock'].map(f =>
stat(path.join(root, f)).then(() => f, () => null),
),
)).filter(Boolean);
if (lockFiles.length) {
return lockFiles;
}
}
if (!files) {
files = ['package.json'];
}
if (!directories) {
directories = ['node_modules'];
}
directories = directories.map(d => `${d}/*`);
return flatten([files, directories]);
};
module.exports = options => {
options = options || {};
const root = options.root || pkgDir.sync(process.cwd());
let files = options.files;
let directories = options.directories;
let hashDefaults = Promise.resolve();
if (!files && !directories) {
hashDefaults = hashFiles(root, ['package-lock.json', 'yarn.lock']);
}
return hashDefaults
.then(_defaults => {
if (_defaults && _defaults.length > 0) {
return [_defaults];
} else {
if (!files) {
files = ['package.json'];
}
if (!directories) {
directories = ['node_modules'];
}
}
return Promise.all([
hashFiles(root, files),
Promise.all(
directories.map(dir =>
readdir(path.join(root, dir))
.then(items =>
Promise.all(
items.map(item =>
stat(path.join(root, dir, item))
.then(stat => {
if (stat.isDirectory()) {
return hashFiles(path.join(root, dir, item), files);
}
if (stat.isFile()) {
return hashFile(path.join(root, dir, item)).then(
hash => (hash ? [hash] : hash),
);
}
})
.catch(function(...args) {
console.error(args);
}),
),
).then(hashes => hashes.filter(Boolean)),
)
.catch(() => {})
.then(flatten),
),
).then(flatten),
]);
})
.then(flatten)
.then(items => {
items.forEach(item => {
item[0] = path.relative(root, item[0]);
});
// console.log(items);
items.sort((a, b) => {
if (a[0] < b[0]) {
return -1;
} else if (a[0] > b[0]) {
return 1;
}
return 0;
});
return hashObject(items);
});
};
module.exports.inputs = inputs;