1
0
mirror of https://github.com/citizenfx/cfx-server-data.git synced 2025-02-13 17:53:16 +08:00

builders: webpack: cache input file state and only rebuild when needing to

This commit is contained in:
moscovium 2019-01-15 14:00:11 +01:00
parent 2bc68781fc
commit 3c6a2b6859
2 changed files with 111 additions and 9 deletions

View File

@ -1,22 +1,68 @@
const fs = require('fs');
const path = require('path'); const path = require('path');
const workerFarm = require('worker-farm'); const workerFarm = require('worker-farm');
const async = require('async'); const async = require('async');
const justBuilt = {};
const webpackBuildTask = { const webpackBuildTask = {
shouldBuild(resourceName) { shouldBuild(resourceName) {
const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config'); const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config');
if (numMetaData > 0) { if (numMetaData > 0) {
if (!(resourceName in justBuilt)) { for (let i = 0; i < numMetaData; i++) {
return true; const configName = GetResourceMetadata(resourceName, 'webpack_config');
}
delete justBuilt[resourceName]; if (shouldBuild(configName)) {
return true;
}
}
} }
return false; return false;
function loadCache(config) {
const cachePath = `cache/${resourceName}/${config.replace(/\//g, '_')}.json`;
try {
return JSON.parse(fs.readFileSync(cachePath, { encoding: 'utf8' }));
} catch {
return null;
}
}
function shouldBuild(config) {
const cache = loadCache(config);
if (!cache) {
return true;
}
for (const file of cache) {
const stats = getStat(file.name);
if (!stats ||
stats.mtime !== file.stats.mtime ||
stats.size !== file.stats.size ||
stats.inode !== file.stats.inode) {
return true;
}
}
return false;
}
function getStat(path) {
try {
const stat = fs.statSync(path);
return stat ? {
mtime: stat.mtimeMs,
size: stat.size,
inode: stat.ino,
} : null;
} catch {
return null;
}
}
}, },
build(resourceName, cb) { build(resourceName, cb) {
@ -30,6 +76,12 @@ const webpackBuildTask = {
async.forEachOf(configs, (configName, i, acb) => { async.forEachOf(configs, (configName, i, acb) => {
const configPath = GetResourcePath(resourceName) + '/' + configName; const configPath = GetResourcePath(resourceName) + '/' + configName;
const cachePath = `cache/${resourceName}/${configName.replace(/\//g, '_')}.json`;
try {
fs.mkdirSync(path.dirname(cachePath));
} catch {}
const config = require(configPath); const config = require(configPath);
const workers = workerFarm(require.resolve('./webpack_runner')); const workers = workerFarm(require.resolve('./webpack_runner'));
@ -39,7 +91,8 @@ const webpackBuildTask = {
workers({ workers({
configPath, configPath,
resourcePath resourcePath,
cachePath
}, (err, outp) => { }, (err, outp) => {
workerFarm.end(workers); workerFarm.end(workers);
@ -61,6 +114,8 @@ const webpackBuildTask = {
return; return;
} }
console.log(`${resourceName}: built ${configName}`);
acb(); acb();
}); });
@ -75,8 +130,6 @@ const webpackBuildTask = {
return; return;
} }
justBuilt[resourceName] = true;
cb(true); cb(true);
}); });
}); });

View File

@ -1,5 +1,48 @@
const weebpack = require('webpack'); const weebpack = require('webpack');
const path = require('path'); const path = require('path');
const fs = require('fs');
function getStat(path) {
try {
const stat = fs.statSync(path);
return stat ? {
mtime: stat.mtimeMs,
size: stat.size,
inode: stat.ino,
} : null;
} catch {
return null;
}
}
class SaveStatePlugin {
constructor(inp) {
this.cache = [];
this.cachePath = inp.cachePath;
}
apply(compiler) {
compiler.hooks.afterCompile.tap('SaveStatePlugin', (compilation) => {
for (const file of compilation.fileDependencies) {
this.cache.push({
name: file,
stats: getStat(file)
});
}
});
compiler.hooks.done.tap('SaveStatePlugin', (stats) => {
if (stats.hasErrors()) {
return;
}
fs.writeFile(this.cachePath, JSON.stringify(this.cache), () => {
});
});
}
}
module.exports = (inp, callback) => { module.exports = (inp, callback) => {
const config = require(inp.configPath); const config = require(inp.configPath);
@ -10,6 +53,12 @@ module.exports = (inp, callback) => {
config.output.path = path.resolve(inp.resourcePath, config.output.path); config.output.path = path.resolve(inp.resourcePath, config.output.path);
} }
if (!config.plugins) {
config.plugins = [];
}
config.plugins.push(new SaveStatePlugin(inp));
weebpack(config, (err, stats) => { weebpack(config, (err, stats) => {
if (err) { if (err) {
callback(err); callback(err);