diff --git a/README.md b/README.md index 28d4dfc1f..494ab2903 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ The following options are also supported: * `-h`, `--help` ............. Display help information * `-m`, `--minify` ......... Write only the minified production output * `-o`, `--output` ......... Write output to a given path/filename - * `-p`, `--source-map` .. Generate a source map for the minified output + * `-p`, `--source-map` .. Generate a source map for the minified output, using an optional source map URL * `-s`, `--silent` ......... Skip status updates normally logged to the console * `-V`, `--version` ....... Output current version of Lo-Dash diff --git a/build.js b/build.js index d9b255327..d87c45dfd 100755 --- a/build.js +++ b/build.js @@ -594,7 +594,7 @@ ' -h, --help Display help information', ' -m, --minify Write only the minified production output', ' -o, --output Write output to a given path/filename', - ' -p, --source-map Generate a source map for the minified output', + ' -p, --source-map Generate a source map for the minified output, using an optional source map URL', ' -s, --silent Skip status updates normally logged to the console', ' -V, --version Output current version of Lo-Dash', '' @@ -1304,13 +1304,16 @@ // the debug version of `source` var debugSource; + // used to specify the source map URL + var sourceMapURL; + // used to report invalid command-line arguments var invalidArgs = _.reject(options.slice(options[0] == 'node' ? 2 : 0), function(value, index, options) { if (/^(?:-o|--output)$/.test(options[index - 1]) || /^(?:category|exclude|exports|iife|include|moduleId|minus|plus|settings|template)=.*$/.test(value)) { return true; } - return [ + var result = [ 'backbone', 'csp', 'legacy', @@ -1328,6 +1331,12 @@ '-s', '--silent', '-V', '--version' ].indexOf(value) > -1; + + if (!result && /^(?:-p|--source-map)$/.test(options[index - 1])) { + result = true; + sourceMapURL = value; + } + return result; }); // report invalid arguments @@ -2440,6 +2449,7 @@ 'isTemplate': isTemplate, 'modes': isIIFE && ['simple', 'hybrid'], 'outputPath': outputPath, + 'sourceMapURL': sourceMapURL, 'onComplete': function(data) { if (isCustom) { data.source = addCommandsToHeader(data.source, options); diff --git a/build/minify.js b/build/minify.js index 81e4d295d..743fe3e90 100755 --- a/build/minify.js +++ b/build/minify.js @@ -7,8 +7,9 @@ https = require('https'), path = require('path'), spawn = require('child_process').spawn, + zlib = require('zlib'), tar = require('../vendor/tar/tar.js'), - zlib = require('zlib'); + _ = require('../lodash.js'); /** Load other modules */ var preprocess = require('./pre-compile.js'), @@ -80,7 +81,12 @@ * onComplete - The function called once minification has finished. */ function minify(source, options) { + // used to specify the source map URL + var sourceMapURL; + + // used to specify the default minifer modes var modes = ['simple', 'advanced', 'hybrid']; + source || (source = ''); options || (options = {}); @@ -89,6 +95,35 @@ // convert commands to an options object options = source; + // used to report invalid command-line arguments + var invalidArgs = _.reject(options.slice(options[0] == 'node' ? 2 : 0), function(value, index, options) { + if (/^(?:-o|--output)$/.test(options[index - 1]) || + /^modes=.*$/.test(value)) { + return true; + } + var result = [ + '-o', '--output', + '-p', '--source-map', + '-s', '--silent', + '-t', '--template' + ].indexOf(value) > -1; + + if (!result && /^(?:-p|--source-map)$/.test(options[index - 1])) { + result = true; + sourceMapURL = value; + } + return result; + }); + + // report invalid arguments + if (invalidArgs.length) { + console.log( + '\n' + + 'Invalid argument' + (invalidArgs.length > 1 ? 's' : '') + + ' passed: ' + invalidArgs.join(', ') + ); + return; + } var filePath = options[options.length - 1], isMapped = options.indexOf('-p') > -1 || options.indexOf('--source-map') > -1, isSilent = options.indexOf('-s') > -1 || options.indexOf('--silent') > -1, @@ -114,7 +149,8 @@ 'isSilent': isSilent, 'isTemplate': isTemplate, 'modes': modes, - 'outputPath': outputPath + 'outputPath': outputPath, + 'sourceMapURL': sourceMapURL }; source = fs.readFileSync(filePath, 'utf8'); @@ -186,6 +222,7 @@ this.isSilent = !!options.isSilent; this.isTemplate = !!options.isTemplate; this.outputPath = options.outputPath; + this.sourceMapURL = options.sourceMapURL; var modes = this.modes = options.modes; source = this.source = preprocess(source, options); @@ -304,10 +341,11 @@ function closureCompile(source, mode, callback) { var filePath = this.filePath, isAdvanced = mode == 'advanced', - outputPath = this.outputPath, isMapped = this.isMapped, + options = closureOptions.slice(), + outputPath = this.outputPath, mapPath = getMapPath(outputPath), - options = closureOptions.slice(); + sourceMapURL = this.sourceMapURL || path.basename(mapPath); // remove copyright header to make other modifications easier var license = (/^(?:\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*/.exec(source) || [''])[0]; @@ -369,7 +407,7 @@ if (isMapped) { var mapOutput = fs.readFileSync(mapPath, 'utf8'); fs.unlinkSync(mapPath); - output = output.replace(/[\s;]*$/, '\n/*\n//@ sourceMappingURL=' + path.basename(mapPath)) + '\n*/'; + output = output.replace(/[\s;]*$/, '\n/*\n//@ sourceMappingURL=' + sourceMapURL) + '\n*/'; mapOutput = JSON.parse(mapOutput); mapOutput.file = path.basename(outputPath); diff --git a/test/test-build.js b/test/test-build.js index 64a4dba3d..11f76e73a 100644 --- a/test/test-build.js +++ b/test/test-build.js @@ -645,7 +645,9 @@ (function() { var mapCommands = [ '-p', - '--source-map' + '-p custom.map', + '--source-map', + '--source-map custom.map' ]; var outputCommands = [ @@ -661,9 +663,10 @@ var basename = path.basename(data.outputPath, '.js'), comment = (/(\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)$/.exec(data.source) || [])[0], sources = /foo.js/.test(outputCommand) ? ['foo.js'] : ['lodash' + (outputCommand.length ? '' : '.custom') + '.js'], - sourceMap = JSON.parse(data.sourceMap); + sourceMap = JSON.parse(data.sourceMap), + sourceMapURL = (/\w+(?=\.map$)/.exec(mapCommand) || [basename])[0]; - ok(RegExp('/\\*\\n//@ sourceMappingURL=' + basename + '.map\\n\\*/').test(comment), basename); + ok(RegExp('/\\*\\n//@ sourceMappingURL=' + sourceMapURL + '.map\\n\\*/').test(comment), basename); equal(sourceMap.file, basename + '.js', basename); deepEqual(sourceMap.sources, sources, basename); @@ -674,7 +677,7 @@ if (outputCommand.indexOf('-m') < 0) { callback = _.after(2, callback); } - build(['-s', mapCommand].concat(outputCommand), callback); + build(['-s'].concat(mapCommand.split(' '), outputCommand), callback); }); }); });