From 14a447b3d8376169200d6c437330aa2a398a12b8 Mon Sep 17 00:00:00 2001 From: Kit Cambridge Date: Sun, 19 May 2013 14:14:33 -0700 Subject: [PATCH] Ensure that the `javaOptions` are set correctly, as `exec` is asynchronous. Previously, the `java` command would execute on the next tick and update the `javaOptions` array, which could occur prior to the invocation of the Closure Compiler on the current tick. This has now been refactored into a separate `getJavaOptions` function, which passes the `javaOptions` array to a callback. `getJavaOptions` is defined lazily; after the first invocation, the options are cached and passed to all subsequent callbacks. The callbacks are invoked on the next tick for compatibility with `exec`. Former-commit-id: 89ca63c9edb3df3d4fcbbaa64e06075495febfd0 --- build/minify.js | 124 +++++++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/build/minify.js b/build/minify.js index 31ed8f89e..4d9c8997f 100755 --- a/build/minify.js +++ b/build/minify.js @@ -60,15 +60,30 @@ }()); /** - * Java command-line options used for faster minification. + * Retrieves the Java command-line options used for faster minification by + * the Closure Compiler, invoking the `callback` when finished. Subsequent + * invocations will lazily return the original options. The callback is + * invoked with one argument: `(javaOptions)`. + * * See https://code.google.com/p/closure-compiler/wiki/FAQ#What_are_the_recommended_Java_VM_command-line_options?. + * + * @param {Function} callback The function called once the options have + * been retrieved. */ - var javaOptions = []; - cp.exec('java -version -client -d32', function(error) { - if (!error && process.platform != 'win32') { - javaOptions.push('-client', '-d32'); - } - }); + function getJavaOptions(callback) { + var javaOptions = []; + cp.exec('java -version -client -d32', function(error) { + if (!error && process.platform != 'win32') { + javaOptions.push('-client', '-d32'); + } + getJavaOptions = function getJavaOptions(callback) { + process.nextTick(function () { + callback(javaOptions); + }); + }; + callback(javaOptions); + }); + } /** The Closure Compiler optimization modes */ var optimizationModes = { @@ -386,57 +401,60 @@ if (isMapped) { options.push('--create_source_map=' + mapPath, '--source_map_format=V3'); } - var compiler = cp.spawn('java', javaOptions.concat('-jar', closurePath, options)); - if (!this.isSilent) { - console.log('Compressing ' + path.basename(outputPath, '.js') + ' using the Closure Compiler (' + mode + ')...'); - } - var error = ''; - compiler.stderr.on('data', function(data) { - error += data; - }); + getJavaOptions(function onJavaOptions(javaOptions) { + var compiler = cp.spawn('java', javaOptions.concat('-jar', closurePath, options)); + if (!this.isSilent) { + console.log('Compressing ' + path.basename(outputPath, '.js') + ' using the Closure Compiler (' + mode + ')...'); + } - var output = ''; - compiler.stdout.on('data', function(data) { - output += data; - }); + var error = ''; + compiler.stderr.on('data', function(data) { + error += data; + }); - compiler.on('exit', function(status) { - // `status` contains the process exit code - if (status) { - var exception = new Error(error); - exception.status = status; - } - // restore IIFE and move exposed vars inside the IIFE - if (hasIIFE && isAdvanced) { - output = output - .replace(/__iife__\(/, '(') - .replace(/,\s*this\)([\s;]*(\n\/\/.+)?)$/, '(this))$1') - .replace(/^((?:var (?:\w+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^{]+{)/, '$2$1'); - } - // inject "use strict" directive - if (isStrict) { - output = output.replace(/^[\s\S]*?function[^{]+{/, '$&"use strict";'); - } - // restore copyright header - if (license) { - output = license + output; - } - if (isMapped) { - var mapOutput = fs.readFileSync(mapPath, 'utf8'); - fs.unlinkSync(mapPath); - output = output.replace(/[\s;]*$/, '\n/*\n//@ sourceMappingURL=' + sourceMapURL) + '\n*/'; + var output = ''; + compiler.stdout.on('data', function(data) { + output += data; + }); - mapOutput = JSON.parse(mapOutput); - mapOutput.file = path.basename(outputPath); - mapOutput.sources = [path.basename(filePath)]; - mapOutput = JSON.stringify(mapOutput, null, 2); - } - callback(exception, output, mapOutput); - }); + compiler.on('exit', function(status) { + // `status` contains the process exit code + if (status) { + var exception = new Error(error); + exception.status = status; + } + // restore IIFE and move exposed vars inside the IIFE + if (hasIIFE && isAdvanced) { + output = output + .replace(/__iife__\(/, '(') + .replace(/,\s*this\)([\s;]*(\n\/\/.+)?)$/, '(this))$1') + .replace(/^((?:var (?:\w+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^{]+{)/, '$2$1'); + } + // inject "use strict" directive + if (isStrict) { + output = output.replace(/^[\s\S]*?function[^{]+{/, '$&"use strict";'); + } + // restore copyright header + if (license) { + output = license + output; + } + if (isMapped) { + var mapOutput = fs.readFileSync(mapPath, 'utf8'); + fs.unlinkSync(mapPath); + output = output.replace(/[\s;]*$/, '\n/*\n//@ sourceMappingURL=' + sourceMapURL) + '\n*/'; - // proxy the standard input to the Closure Compiler - compiler.stdin.end(source); + mapOutput = JSON.parse(mapOutput); + mapOutput.file = path.basename(outputPath); + mapOutput.sources = [path.basename(filePath)]; + mapOutput = JSON.stringify(mapOutput, null, 2); + } + callback(exception, output, mapOutput); + }); + + // proxy the standard input to the Closure Compiler + compiler.stdin.end(source); + }.bind(this)); } /**