grunt-contrib-uglify = function (grunt) {
// Internal lib.
var uglify = require('./lib/uglify').init(grunt);
var getAvailableFiles = function (filesArray) {
return filesArray.filter(function (filepath) {
if (!grunt.file.exists(filepath)) {
grunt.log.warn('Source file ' + chalk.cyan(filepath) + ' not found');
return false;
}
return true;
});
};
grunt.registerMultiTask('uglify', 'Minify files with UglifyJS.', function() {
// Merge task-specific and/or target-specific options with these defaults.
var options = this.options({
banner: '',
footer: '',
compress: {
warnings: false
},
mangle: {},
beautify: false,
report: 'min',
expression: false,
maxLineLen: 32000,
ASCIIOnly: false,
screwIE8: true,
quoteStyle: 0
});
var footer = normalizeLf(options.footer);
var mapNameGenerator, mapInNameGenerator;
var created = {
maps: 0,
files: 0
};
var size = {
before: 0,
after: 0
};
// Iterate over all src-dest file pairs.
this.files.forEach(function (f) {
var availableFiles = getAvailableFiles(f.src);
if (availableFiles.length === 0) {
grunt.log.warn('Destination ' + chalk.cyan(f.dest) + ' not written because src files were empty.');
return;
}
// Warn on incompatible options
if (options.expression && (options.compress || options.mangle)) {
grunt.log.warn('Option ' + chalk.cyan('expression') + ' not compatible with ' + chalk.cyan('compress and mangle'));
options.compress = false;
options.mangle = false;
}
// function to get the name of the sourceMap
if (typeof options.sourceMapName === 'function') {
mapNameGenerator = options.sourceMapName;
}
// function to get the name of the sourceMapIn file
if (typeof options.sourceMapIn === 'function') {
if (availableFiles.length !== 1) {
grunt.fail.warn('Cannot generate `sourceMapIn` for multiple source files.');
}
mapInNameGenerator = options.sourceMapIn;
}
// dynamically create destination sourcemap name
if (mapNameGenerator) {
try {
options.generatedSourceMapName = mapNameGenerator(f.dest);
} catch (e) {
err = new Error('SourceMap failed.');
err.origError = e;
grunt.fail.warn(err);
}
// If no name is passed append .map to the filename
} else if (!options.sourceMapName) {
options.generatedSourceMapName = f.dest + '.map';
} else {
options.generatedSourceMapName = options.sourceMapName;
}
// Dynamically create incoming sourcemap names
if (mapInNameGenerator) {
try {
options.sourceMapIn = mapInNameGenerator(availableFiles[0]);
} catch (e) {
err = new Error('SourceMapInName failed.');
err.origError = e;
grunt.fail.warn(err);
}
}
// Calculate the path from the dest file to the sourcemap for the
// sourceMappingURL reference
// If sourceMapUrl is defined, use this instead
if (options.sourceMap) {
var destToSourceMapPath, sourceMapBasename;
if (!options.sourceMapUrl) {
destToSourceMapPath = relativePath(f.dest, options.generatedSourceMapName);
sourceMapBasename = path.basename(options.generatedSourceMapName);
options.destToSourceMap = destToSourceMapPath + sourceMapBasename;
} else {
options.destToSourceMap = options.sourceMapUrl;
}
}
// Minify files, warn and fail on error.
var result;
try {
result = uglify.minify(availableFiles, f.dest, options);
} catch (e) {
console.log(e);
err = new Error('Uglification failed.');
if (e.message) {
err.message += '\n' + e.message + '. \n';
if (e.line) {
err.message += 'Line ' + e.line + ' in ' + availableFiles + '\n';
}
}
err.orig ...n/a
init = function (grunt) {
var exports = {};
// Minify with UglifyJS.
// From https://github.com/mishoo/UglifyJS2
// API docs at http://lisperator.net/uglifyjs/
exports.minify = function(files, dest, options) {
options = options || {};
grunt.verbose.write('Minifying with UglifyJS...');
var topLevel = null;
var totalCode = '';
var sourcesContent = {};
var outputOptions = getOutputOptions(options, dest);
var output = UglifyJS.OutputStream(outputOptions);
// Grab and parse all source files
files.forEach(function(file) {
var code = grunt.file.read(file);
totalCode += code;
// The src file name must be relative to the source map for things to work
var basename = path.basename(file);
var fileDir = path.dirname(file);
var sourceMapDir = path.dirname(options.generatedSourceMapName);
var relativePath = path.relative(sourceMapDir, fileDir);
var pathPrefix = relativePath ? relativePath + path.sep : '';
var bare_returns = options.bare_returns || undefined;
// Convert paths to use forward slashes for sourcemap use in the browser
file = uriPath(pathPrefix + basename);
sourcesContent[file] = code;
topLevel = UglifyJS.parse(code, {
filename: file,
toplevel: topLevel,
expression: options.expression,
bare_returns: bare_returns
});
});
// Wrap code in a common js wrapper.
if (options.wrap) {
topLevel = topLevel.wrap_commonjs(options.wrap, options.exportAll);
}
// Wrap code in closure with configurable arguments/parameters list.
if (options.enclose) {
var argParamList = Object.keys(options.enclose).map(function(key) {
return key + ':' + options.enclose[key];
});
topLevel = topLevel.wrap_enclose(argParamList);
}
var topLevelCache = null;
if (options.nameCache) {
topLevelCache = UglifyJS.readNameCache(options.nameCache, 'vars');
}
// Need to call this before we mangle or compress,
// and call after any compression or ast altering
if (options.expression === false) {
topLevel.figure_out_scope({
screw_ie8: options.screwIE8,
cache: topLevelCache
});
}
if (options.compress !== false) {
if (options.compress === true) {
options.compress = {};
}
if (options.compress.warnings !== true) {
options.compress.warnings = false;
}
if (options.screwIE8 === false) {
options.compress.screw_ie8 = false;
}
var compressor = UglifyJS.Compressor(options.compress);
topLevel = compressor.compress(topLevel);
// Need to figure out scope again after source being altered
if (options.expression === false) {
topLevel.figure_out_scope({
screw_ie8: options.screwIE8,
cache: topLevelCache
});
}
}
var mangleExclusions = {
vars: [],
props: []
};
if (options.reserveDOMProperties) {
mangleExclusions = UglifyJS.readDefaultReservedFile();
}
if (options.exceptionsFiles) {
try {
options.exceptionsFiles.forEach(function(filename) {
mangleExclusions = UglifyJS.readReservedFile(filename, mangleExclusions);
});
} catch (ex) {
grunt.warn(ex);
}
}
var cache = null;
if (options.nameCache) {
cache = UglifyJS.readNameCache(options.nameCache, 'props');
}
if (typeof options.mangleProperties !== 'undefined' && options.mangleProperties !== false) {
// if options.mangleProperties is a boolean (true) convert it into an object
if (typeof options.mangleProperties !== 'object') {
options.mangleProperties = {};
}
options.mangleProperties.reserved = mangleExclusions ? mangleExclusions.props : null;
options.mangleProperties.cache = cache;
topLevel = UglifyJS.mangle_properties(topLevel, options.mangleProperties);
if (options.nameCache) {
UglifyJS.writeNameCache(options.nameCache, 'props', cache);
} ......
// Converts \r\n to \n
function normalizeLf(string) {
return string.replace(/\r\n/g, '\n');
}
module.exports = function(grunt) {
// Internal lib.
var uglify = require('./lib/uglify').init(grunt);
var getAvailableFiles = function (filesArray) {
return filesArray.filter(function (filepath) {
if (!grunt.file.exists(filepath)) {
grunt.log.warn('Source file ' + chalk.cyan(filepath) + ' not found');
return false;
}
...