diff --git a/index.js b/index.js index deaea00..7c6af69 100644 --- a/index.js +++ b/index.js @@ -1,93 +1,7 @@ 'use strict'; -var through = require('through2'), - uglify = require('uglify-js'), - merge = require('deepmerge'), - PluginError = require('gulp-util/lib/PluginError'), - applySourceMap = require('vinyl-sourcemaps-apply'), - reSourceMapComment = /\n\/\/# sourceMappingURL=.+?$/, - pluginName = 'gulp-uglify'; +var uglfiy = require('uglify-js'); +var minifier = require('./minifier'); -function minify(file, options) { - var mangled; - - try { - mangled = uglify.minify(String(file.contents), options); - mangled.code = new Buffer(mangled.code.replace(reSourceMapComment, '')); - return mangled; - } catch (e) { - return createError(file, e); - } -} - -function setup(opts) { - var options = merge(opts || {}, { - fromString: true, - output: {} - }); - - if (options.preserveComments === 'all') { - options.output.comments = true; - } else if (options.preserveComments === 'some') { - // preserve comments with directives or that start with a bang (!) - options.output.comments = /^!|@preserve|@license|@cc_on/i; - } else if (typeof options.preserveComments === 'function') { - options.output.comments = options.preserveComments; - } - - return options; -} - -function createError(file, err) { - if (typeof err === 'string') { - return new PluginError(pluginName, file.path + ': ' + err, { - fileName: file.path, - showStack: false - }); - } - - var msg = err.message || err.msg || /* istanbul ignore next */ 'unspecified error'; - - return new PluginError(pluginName, file.path + ': ' + msg, { - fileName: file.path, - lineNumber: err.line, - stack: err.stack, - showStack: false - }); -} - -module.exports = function(opt) { - - function uglify(file, encoding, callback) { - var options = setup(opt); - - if (file.isNull()) { - return callback(null, file); - } - - if (file.isStream()) { - return callback(createError(file, 'Streaming not supported')); - } - - if (file.sourceMap) { - options.outSourceMap = file.relative; - } - - var mangled = minify(file, options); - - if (mangled instanceof PluginError) { - return callback(mangled); - } - - file.contents = mangled.code; - - if (file.sourceMap) { - var sourceMap = JSON.parse(mangled.map); - sourceMap.sources = [file.relative]; - applySourceMap(file, sourceMap); - } - - callback(null, file); - } - - return through.obj(uglify); +module.exports = function(opts) { + return minifier(opts, uglfiy); }; diff --git a/minifier.js b/minifier.js new file mode 100644 index 0000000..c102753 --- /dev/null +++ b/minifier.js @@ -0,0 +1,91 @@ +'use strict'; +var through = require('through2'); +var deap = require('deap'); +var PluginError = require('gulp-util/lib/PluginError'); +var applySourceMap = require('vinyl-sourcemaps-apply'); +var reSourceMapComment = /\n\/\/# sourceMappingURL=.+?$/; +var pluginName = 'gulp-uglify'; + +function trycatch(fn, handle) { + try { + return fn(); + } catch (e) { + return handle(e); + } +} + +function setup(opts) { + var options = deap({}, opts, { + fromString: true, + output: {} + }); + + if (options.preserveComments === 'all') { + options.output.comments = true; + } else if (options.preserveComments === 'some') { + // preserve comments with directives or that start with a bang (!) + options.output.comments = /^!|@preserve|@license|@cc_on/i; + } else if (typeof options.preserveComments === 'function') { + options.output.comments = options.preserveComments; + } + + return options; +} + +function createError(file, err) { + if (typeof err === 'string') { + return new PluginError(pluginName, file.path + ': ' + err, { + fileName: file.path, + showStack: false + }); + } + + var msg = err.message || err.msg || /* istanbul ignore next */ 'unspecified error'; + + return new PluginError(pluginName, file.path + ': ' + msg, { + fileName: file.path, + lineNumber: err.line, + stack: err.stack, + showStack: false + }); +} + +module.exports = function(opts, uglify) { + function minify(file, encoding, callback) { + var options = setup(opts || {}); + + if (file.isNull()) { + return callback(null, file); + } + + if (file.isStream()) { + return callback(createError(file, 'Streaming not supported')); + } + + if (file.sourceMap) { + options.outSourceMap = file.relative; + } + + var mangled = trycatch(function() { + var m = uglify.minify(String(file.contents), options); + m.code = new Buffer(m.code.replace(reSourceMapComment, '')); + return m; + }, createError.bind(null, file)); + + if (mangled instanceof PluginError) { + return callback(mangled); + } + + file.contents = mangled.code; + + if (file.sourceMap) { + var sourceMap = JSON.parse(mangled.map); + sourceMap.sources = [file.relative]; + applySourceMap(file, sourceMap); + } + + callback(null, file); + } + + return through.obj(minify); +}; diff --git a/package.json b/package.json index 3692dbb..59f37b1 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Terin Stock ", "bugs": "https://github.com/terinjokes/gulp-uglify/issues", "dependencies": { - "deepmerge": ">=0.2.7 <0.3.0-0", + "deap": ">=1.0.0 <2.0.0-0", "gulp-util": ">=3.0.0 <4.0.0-0", "through2": ">=0.6.1 <1.0.0-0", "uglify-js": "2.4.16", @@ -14,6 +14,7 @@ "devDependencies": { "argg": "0.0.1", "codeclimate-test-reporter": "0.0.3", + "cmem": ">=1.0.0 <2.0.0-0", "gulp-concat": ">=2.3.4 <3.0.0-0", "gulp-sourcemaps": ">=1.1.1 <2.0.0-0", "istanbul": ">=0.3.0 <0.4.0-0", diff --git a/test/injectable.js b/test/injectable.js new file mode 100644 index 0000000..e499cbe --- /dev/null +++ b/test/injectable.js @@ -0,0 +1,50 @@ +'use strict'; +var test = require('tape'); +var Vinyl = require('vinyl'); +var minifer = require('../minifier'); +var cmem = require('cmem'); + +var testContentsOutput = 'function abs(a, b) {\n return a > b; }'; +var testContentsInput = 'function testInput() {}'; +var testFile = new Vinyl({ + cwd: '/home/terin/broken-promises/', + base: '/home/terin/broken-promises/test', + path: '/home/terin/broken-promises/test/test1.js', + contents: new Buffer(testContentsInput) +}); +var uglifyjs = { + minify: cmem(function() { + return { + code: testContentsOutput + }; + }) +}; + +test('should minify files', function(t) { + t.plan(10); + + var stream = minifer({injecting: true}, uglifyjs); + + stream.on('data', function(newFile) { + t.ok(newFile, 'emits a file'); + t.ok(newFile.path, 'file has a path'); + t.ok(newFile.relative, 'file has relative path information'); + t.ok(newFile.contents, 'file has contents'); + + t.ok(newFile instanceof Vinyl, 'file is Vinyl'); + t.ok(newFile.contents instanceof Buffer, 'file contents are a buffer'); + + t.equals(String(newFile.contents), testContentsOutput); + + t.equals(uglifyjs.minify.$count, 1, 'minify stub was called only once'); + t.equals(uglifyjs.minify.$args[0], testContentsInput, 'stub argument 0 was the expected input'); + t.deepEqual(uglifyjs.minify.$args[1], { + fromString: true, + output: {}, + injecting: true + }, 'stub argument 1 was the expected options'); + }); + + stream.write(testFile); + stream.end(); +});