diff --git a/resources/[system]/[builders]/webpack/webpack_builder.js b/resources/[system]/[builders]/webpack/webpack_builder.js index c2aa6b3..51793d3 100644 --- a/resources/[system]/[builders]/webpack/webpack_builder.js +++ b/resources/[system]/[builders]/webpack/webpack_builder.js @@ -2,138 +2,155 @@ const fs = require('fs'); const path = require('path'); const workerFarm = require('worker-farm'); const async = require('async'); - +let buildingInProgress = false; +let currentBuildingModule = ''; +let currentBuildingScript = ''; const webpackBuildTask = { - shouldBuild(resourceName) { - const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config'); - - if (numMetaData > 0) { - for (let i = 0; i < numMetaData; i++) { - const configName = GetResourceMetadata(resourceName, 'webpack_config'); + shouldBuild(resourceName) { + const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config'); - if (shouldBuild(configName)) { - return true; - } - } - } - - return false; + if (numMetaData > 0) { + for (let i = 0; i < numMetaData; i++) { + const configName = GetResourceMetadata(resourceName, 'webpack_config'); - 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) { - const configs = []; - const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config'); - - for (let i = 0; i < numMetaData; i++) { - configs.push(GetResourceMetadata(resourceName, 'webpack_config', i)); - } - - async.forEachOf(configs, (configName, i, acb) => { - const configPath = GetResourcePath(resourceName) + '/' + configName; + if (shouldBuild(configName)) { + return true; + } + } + } - const cachePath = `cache/${resourceName}/${configName.replace(/\//g, '_')}.json`; + return false; - try { - fs.mkdirSync(path.dirname(cachePath)); - } catch {} - - const config = require(configPath); - - const workers = workerFarm(require.resolve('./webpack_runner')); - - if (config) { - const resourcePath = path.resolve(GetResourcePath(resourceName)); - - workers({ - configPath, - resourcePath, - cachePath - }, (err, outp) => { - workerFarm.end(workers); - - if (err) { - console.error(err.stack || err); - if (err.details) { - console.error(err.details); - } - - acb("worker farm webpack errored out"); - return; - } - - if (outp.errors) { - for (const error of outp.errors) { - console.log(error); - } - acb("webpack got an error"); - return; - } + function loadCache(config) { + const cachePath = `cache/${resourceName}/${config.replace(/\//g, '_')}.json`; - console.log(`${resourceName}: built ${configName}`); - - acb(); - }); - - return; - } - - acb("no configuration"); - }, (err) => { - setImmediate(() => { - if (err) { - cb(false, err); - return; - } - - cb(true); - }); - }); - } + 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) { + let buildWebpack = async () => { + let error = null; + const configs = []; + const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config'); + + for (let i = 0; i < numMetaData; i++) { + configs.push(GetResourceMetadata(resourceName, 'webpack_config', i)); + } + for (const configName of configs) { + 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 workers = workerFarm(require.resolve('./webpack_runner')); + + if (config) { + const resourcePath = path.resolve(GetResourcePath(resourceName)); + + while (buildingInProgress) { + console.log(`webpack is busy by another process: we are waiting to compile ${resourceName} (${configName})`); + await sleep(3000); + } + buildingInProgress = true; + currentBuildingModule = resourceName; + currentBuildingScript = configName; + workers({ + configPath, + resourcePath, + cachePath + }, (err, outp) => { + workerFarm.end(workers); + + if (err) { + console.error(err.stack || err); + if (err.details) { + console.error(err.details); + } + + buildingInProgress = false; + currentBuildingModule = ''; + currentBuildingScript = ''; + error = "worker farm webpack errored out"; + console.error("worker farm webpack errored out"); + return; + } + + if (outp.errors) { + for (const error of outp.errors) { + console.log(error); + } + buildingInProgress = false; + currentBuildingModule = ''; + currentBuildingScript = ''; + error = "webpack got an error"; + console.error("webpack got an error"); + return; + } + + console.log(`${resourceName}: built ${configName}`); + + buildingInProgress = false; + currentBuildingModule = ''; + currentBuildingScript = ''; + }); + } + } + if (error) { + cb(false, error); + } else cb(true); + }; + buildWebpack().then(); + } +}; + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); } -RegisterResourceBuildTaskFactory('z_webpack', () => webpackBuildTask); \ No newline at end of file +RegisterResourceBuildTaskFactory('z_webpack', () => webpackBuildTask); diff --git a/resources/[system]/[builders]/yarn/yarn_builder.js b/resources/[system]/[builders]/yarn/yarn_builder.js index 6293d84..84c9fc0 100644 --- a/resources/[system]/[builders]/yarn/yarn_builder.js +++ b/resources/[system]/[builders]/yarn/yarn_builder.js @@ -1,6 +1,8 @@ const path = require('path'); const fs = require('fs'); const child_process = require('child_process'); +let buildingInProgress = false; +let currentBuildingModule = ''; const yarnBuildTask = { shouldBuild(resourceName) { @@ -30,33 +32,49 @@ const yarnBuildTask = { }, build(resourceName, cb) { - const process = child_process.fork( - require.resolve('./yarn_cli.js'), - ['install'], - { - cwd: path.resolve(GetResourcePath(resourceName)) - }); - - process.on('exit', (code, signal) => { - setImmediate(() => { - if (code != 0 || signal) { - cb(false, 'yarn failed!'); - return; - } - - const resourcePath = GetResourcePath(resourceName); - const yarnLock = path.resolve(resourcePath, 'yarn.lock'); - - try { - fs.utimesSync(yarnLock, new Date(), new Date()); - } catch (e) { - - } - - cb(true); - }); - }); - } -} + let buildYarn = async () => { + while (buildingInProgress) { + console.log(`yarn is busy by another process: we are waiting to compile ${resourceName}`); + await sleep(3000); + } + buildingInProgress = true; + currentBuildingModule = resourceName; + const process = child_process.fork( + require.resolve('./yarn_cli.js'), + ['install'], + { + cwd: path.resolve(GetResourcePath(resourceName)) + }); -RegisterResourceBuildTaskFactory('yarn', () => yarnBuildTask); \ No newline at end of file + process.on('exit', (code, signal) => { + setImmediate(() => { + if (code != 0 || signal) { + buildingInProgress = false; + currentBuildingModule = ''; + cb(false, 'yarn failed!'); + return; + } + + const resourcePath = GetResourcePath(resourceName); + const yarnLock = path.resolve(resourcePath, 'yarn.lock'); + + try { + fs.utimesSync(yarnLock, new Date(), new Date()); + } catch (e) { + + } + + buildingInProgress = false; + currentBuildingModule = ''; + cb(true); + }); + }); + }; + buildYarn().then(); + } +}; + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} +RegisterResourceBuildTaskFactory('yarn', () => yarnBuildTask);