UNPKG

5.6 kBJavaScriptView Raw
1var workerFarm = require('worker-farm'),
2 Ajv = require('ajv'),
3 Promise = require('bluebird'),
4 chalk = require('chalk'),
5 assign = require('lodash.assign'),
6 pluralize = require('pluralize'),
7 schema = require('./schema.json'),
8 loadConfigurationFile = require('./src/loadConfigurationFile').default,
9 startWatchIPCServer = require('./src/watchModeIPC').startWatchIPCServer;
10
11var ajv = new Ajv({
12 allErrors: true,
13 coerceTypes: true,
14 removeAdditional: 'all',
15 useDefaults: true
16});
17var validate = ajv.compile(schema);
18
19function notSilent(options) {
20 return !options.json;
21}
22
23function startFarm(config, configPath, options, runWorker, callback) {
24 return Promise.resolve(config).then(function(config) {
25 config = Array.isArray(config) ? config : [config];
26 options = options || {};
27
28 // When in watch mode and a callback is provided start IPC server to invoke callback
29 // once all webpack configurations have been compiled
30 if (options.watch) {
31 startWatchIPCServer(callback, Object.keys(config));
32 }
33
34 if(notSilent(options)) {
35 console.log(chalk.blue('[WEBPACK]') + ' Building ' + chalk.yellow(config.length) + ' ' + pluralize('target', config.length));
36 }
37
38 var builds = config.map(function (c, i) {
39 return runWorker(configPath, options, i, config.length);
40 });
41 if(options.bail) {
42 return Promise.all(builds);
43 } else {
44 return Promise.settle(builds).then(function(results) {
45 return Promise.all(results.map(function (result) {
46 if(result.isFulfilled()) {
47 return result.value();
48 }
49 return Promise.reject(result.reason());
50 }));
51 });
52 }
53 })
54}
55
56/**
57 * Runs the specified webpack configuration in parallel.
58 * @param {String} configPath The path to the webpack.config.js
59 * @param {Object} options
60 * @param {Boolean} [options.watch=false] If `true`, Webpack will run in
61 * `watch-mode`.
62 * @param {Number} [options.maxCallsPerWorker=Infinity] The maximum amount of calls
63 * per parallel worker
64 * @param {Number} [options.maxConcurrentWorkers=require('os').cpus().length] The
65 * maximum number of parallel workers
66 * @param {Number} [options.maxConcurrentCallsPerWorker=10] The maximum number of
67 * concurrent call per prallel worker
68 * @param {Number} [options.maxConcurrentCalls=Infinity] The maximum number of
69 * concurrent calls
70 * @param {Number} [options.maxRetries=0] The maximum amount of retries
71 * on build error
72 * @param {Function} [callback] A callback to be invoked once the build has
73 * been completed
74 * @return {Promise} A Promise that is resolved once all builds have been
75 * created
76 */
77function run(configPath, options, callback) {
78 var config,
79 argvBackup = process.argv,
80 farmOptions = assign({}, options);
81 options = options || {};
82 if(options.colors === undefined) {
83 options.colors = chalk.supportsColor;
84 }
85 if(!options.argv) {
86 options.argv = [];
87 }
88 options.argv.unshift(process.execPath, 'parallel-webpack');
89 try {
90 process.argv = options.argv;
91 config = loadConfigurationFile(configPath);
92 process.argv = argvBackup;
93 } catch(e) {
94 process.argv = argvBackup;
95 return Promise.reject(new Error(
96 chalk.red('[WEBPACK]') + ' Could not load configuration file ' + chalk.underline(configPath) + "\n"
97 + e
98 ));
99 }
100
101 if (!validate(farmOptions)) {
102 return Promise.reject(new Error(
103 'Options validation failed:\n' +
104 validate.errors.map(function(error) {
105 return 'Property: "options' + error.dataPath + '" ' + error.message;
106 }).join('\n')
107 ));
108 }
109
110 var workers = workerFarm(farmOptions, require.resolve('./src/webpackWorker'));
111
112 var shutdownCallback = function() {
113 if (notSilent(options)) {
114 console.log(chalk.red('[WEBPACK]') + ' Forcefully shutting down');
115 }
116 workerFarm.end(workers);
117 };
118
119 function keepAliveAfterFinishCallback(cb){
120 if(options.keepAliveAfterFinish){
121 setTimeout(cb, options.keepAliveAfterFinish);
122 } else {
123 cb();
124 }
125 }
126
127 function finalCallback(){
128 workerFarm.end(workers);
129 process.removeListener("SIGINT", shutdownCallback);
130 }
131
132 process.on('SIGINT', shutdownCallback);
133
134 var startTime = Date.now();
135 var farmPromise = startFarm(
136 config,
137 configPath,
138 options,
139 Promise.promisify(workers),
140 callback
141 ).error(function(err) {
142 if(notSilent(options)) {
143 console.log('%s Build failed after %s seconds', chalk.red('[WEBPACK]'), chalk.blue((Date.now() - startTime) / 1000));
144 }
145 return Promise.reject(err);
146 }).then(function (results) {
147 if(notSilent(options)) {
148 console.log('%s Finished build after %s seconds', chalk.blue('[WEBPACK]'), chalk.blue((Date.now() - startTime) / 1000));
149 }
150 results = results.filter(function(result) {
151 return result;
152 });
153 if(results.length) {
154 return results;
155 }
156 }).finally(function() {
157 keepAliveAfterFinishCallback(finalCallback);
158 });
159
160 if (!options.watch) {
161 farmPromise.asCallback(callback);
162 }
163 return farmPromise;
164}
165
166module.exports = {
167 createVariants: require('./src/createVariants'),
168 run: run
169};