Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: Allow UglifyJS instance to be injected [fixes #77]
It's desirable to allow end users to inject their own version of UglifyJS into the plugin code for two reasons: 1. Allow end users to update to newer versions of UglifyJS without waiting on this project to update, allowing them to easily test unreleased patches in the upstream project. 2. Allows us to more directly test our module's interface between gulp and UglifyJS, and to simplify our unit tests, since we no longer need to worry about the specific UglifyJS output. This commit changes the implementation, allowing UglifyJS to be injected, but does not change the tests to utilize this new feature. This ensures we continue to pass our previous API contract.
- Loading branch information
1 parent
fae2d18
commit 36ffb74
Showing
4 changed files
with
147 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
}); |