Minify modules in a batch

v1.18.x
Peter Jaszkowiak 8 years ago
parent e8caee3c4c
commit 9f5ce24993

@ -88,44 +88,56 @@ module.exports = function (Meta) {
}, },
}; };
function minifyModules(modules, fork, callback) { function copyFile(source, target, cb) {
// for it to never fork var called = false;
// otherwise it spawns way too many processes
// maybe eventually we can pool modules
// and pass the pools to the minifer
// to reduce the total number of threads
fork = false;
async.eachLimit(modules, 500, function (mod, next) { var rd = fs.createReadStream(source);
var srcPath = mod.srcPath; rd.on('error', done);
var destPath = mod.destPath;
async.parallel({ var wr = fs.createWriteStream(target);
dirped: function (cb) { wr.on('error', done);
mkdirp(path.dirname(destPath), cb); wr.on('close', function () {
}, done();
minified: function (cb) { });
fs.readFile(srcPath, function (err, buffer) { rd.pipe(wr);
if (err) {
return cb(err);
}
if (srcPath.endsWith('.min.js') || path.dirname(srcPath).endsWith('min')) { function done(err) {
return cb(null, { code: buffer.toString() }); if (!called) {
cb(err);
called = true;
}
}
} }
minifier.js.minify(buffer.toString(), fork, cb); function minifyModules(modules, fork, callback) {
}); async.eachLimit(modules, 1000, function (mod, next) {
}, mkdirp(path.dirname(mod.destPath), next);
}, function (err, results) { }, function (err) {
if (err) { if (err) {
return next(err); return callback(err);
}
var filtered = modules.reduce(function (prev, mod) {
if (mod.srcPath.endsWith('.min.js') || path.dirname(mod.srcPath).endsWith('min')) {
prev.skip.push(mod);
} else {
prev.minify.push(mod);
} }
var minified = results.minified; return prev;
fs.writeFile(destPath, minified.code, next); }, { minify: [], skip: [] });
async.parallel([
function (cb) {
minifier.js.minifyBatch(filtered.minify, fork, cb);
},
function (cb) {
async.eachLimit(filtered.skip, 500, function (mod, next) {
copyFile(mod.srcPath, mod.destPath, next);
}, cb);
},
], callback);
}); });
}, callback);
} }
function linkModules(callback) { function linkModules(callback) {

@ -38,27 +38,26 @@ function setupDebugging() {
return forkProcessParams; return forkProcessParams;
} }
var children = []; var pool = [];
var free = [];
Minifier.maxThreads = os.cpus().length - 1; Minifier.maxThreads = os.cpus().length - 1;
winston.verbose('[minifier] utilizing a maximum of ' + Minifier.maxThreads + ' additional threads'); winston.verbose('[minifier] utilizing a maximum of ' + Minifier.maxThreads + ' additional threads');
Minifier.killAll = function () { Minifier.killAll = function () {
children.forEach(function (child) { pool.forEach(function (child) {
child.kill('SIGTERM'); child.kill('SIGTERM');
}); });
children = []; pool.length = 0;
}; };
function removeChild(proc) { function getChild() {
children = children.filter(function (child) { if (free.length) {
return child !== proc; return free.shift();
});
} }
function forkAction(action, callback) {
var forkProcessParams = setupDebugging(); var forkProcessParams = setupDebugging();
var proc = childProcess.fork(__filename, [], Object.assign({}, forkProcessParams, { var proc = childProcess.fork(__filename, [], Object.assign({}, forkProcessParams, {
cwd: __dirname, cwd: __dirname,
@ -66,12 +65,26 @@ function forkAction(action, callback) {
minifier_child: true, minifier_child: true,
}, },
})); }));
pool.push(proc);
children.push(proc); return proc;
}
function freeChild(proc) {
proc.removeAllListeners();
free.push(proc);
}
function removeChild(proc) {
var i = pool.indexOf(proc);
pool.splice(i, 1);
}
function forkAction(action, callback) {
var proc = getChild();
proc.on('message', function (message) { proc.on('message', function (message) {
proc.kill(); freeChild(proc);
removeChild(proc);
if (message.type === 'error') { if (message.type === 'error') {
return callback(message.err); return callback(message.err);
@ -102,7 +115,7 @@ if (process.env.minifier_child) {
if (typeof actions[action.act] !== 'function') { if (typeof actions[action.act] !== 'function') {
process.send({ process.send({
type: 'error', type: 'error',
message: 'Unknown action', err: Error('Unknown action'),
}); });
return; return;
} }
@ -126,7 +139,7 @@ if (process.env.minifier_child) {
} }
function executeAction(action, fork, callback) { function executeAction(action, fork, callback) {
if (fork && children.length < Minifier.maxThreads) { if (fork && (pool.length - free.length) < Minifier.maxThreads) {
forkAction(action, callback); forkAction(action, callback);
} else { } else {
if (typeof actions[action.act] !== 'function') { if (typeof actions[action.act] !== 'function') {
@ -155,18 +168,21 @@ function concat(data, callback) {
actions.concat = concat; actions.concat = concat;
function minifyJS(data, callback) { function minifyJS(data, callback) {
var minified; if (data.batch) {
async.eachLimit(data.files, 1000, function (ref, next) {
if (data.fromSource) { var srcPath = ref.srcPath;
var sources = data.source; var destPath = ref.destPath;
var multiple = Array.isArray(sources);
if (!multiple) { fs.readFile(srcPath, function (err, buffer) {
sources = [sources]; if (err && err.code === 'ENOENT') {
return next(null, null);
}
if (err) {
return next(err);
} }
try { try {
minified = sources.map(function (source) { var minified = uglifyjs.minify(buffer.toString(), {
return uglifyjs.minify(source, {
// outSourceMap: data.filename + '.map', // outSourceMap: data.filename + '.map',
compress: data.compress, compress: data.compress,
fromString: true, fromString: true,
@ -175,12 +191,15 @@ function minifyJS(data, callback) {
max_line_len: 400000, max_line_len: 400000,
}, },
}); });
});
fs.writeFile(destPath, minified.code, next);
} catch (e) { } catch (e) {
return callback(e); next(e);
} }
});
}, callback);
return callback(null, multiple ? minified : minified[0]); return;
} }
if (data.files && data.files.length) { if (data.files && data.files.length) {
@ -190,16 +209,16 @@ function minifyJS(data, callback) {
} }
try { try {
minified = uglifyjs.minify(scripts, { var minified = uglifyjs.minify(scripts, {
// outSourceMap: data.filename + '.map', // outSourceMap: data.filename + '.map',
compress: data.compress, compress: data.compress,
fromString: false, fromString: false,
}); });
} catch (e) {
return callback(e);
}
callback(null, minified); callback(null, minified);
} catch (e) {
callback(e);
}
}); });
return; return;
@ -218,11 +237,11 @@ Minifier.js.bundle = function (scripts, minify, fork, callback) {
}, fork, callback); }, fork, callback);
}; };
Minifier.js.minify = function (source, fork, callback) { Minifier.js.minifyBatch = function (scripts, fork, callback) {
executeAction({ executeAction({
act: 'minifyJS', act: 'minifyJS',
fromSource: true, files: scripts,
source: source, batch: true,
}, fork, callback); }, fork, callback);
}; };

Loading…
Cancel
Save