ember-material-icons
Version:
Google Material icons for your ember-cli app
161 lines (133 loc) • 4.88 kB
JavaScript
var walkSync = require('walk-sync');
var Plugin = require('broccoli-plugin');
var UglifyJS = require('uglify-js');
var path = require('path');
var fs = require('fs');
var merge = require('lodash.merge');
var symlinkOrCopy = require('symlink-or-copy');
var mkdirp = require('mkdirp');
var srcURL = require('source-map-url');
var MatcherCollection = require('matcher-collection');
var debug = require('debug')('broccoli-uglify-sourcemap');
module.exports = UglifyWriter;
UglifyWriter.prototype = Object.create(Plugin.prototype);
UglifyWriter.prototype.constructor = UglifyWriter;
function UglifyWriter (inputNodes, options) {
if (!(this instanceof UglifyWriter)) {
return new UglifyWriter(inputNodes, options);
}
inputNodes = Array.isArray(inputNodes) ? inputNodes : [inputNodes];
Plugin.call(this, inputNodes, options);
this.options = merge({
mangle: true,
compress: true,
sourceMapIncludeSources: true
}, options);
this.sourceMapConfig = merge({
enabled: true,
extensions: ['js']
}, this.options.sourceMapConfig);
this.inputNodes = inputNodes;
var exclude = this.options.exclude;
if (Array.isArray(exclude)) {
this.excludes = new MatcherCollection(exclude);
} else {
this.excludes = MatchNothing;
}
}
var MatchNothing = {
match: function () {
return false;
}
};
UglifyWriter.prototype.build = function () {
var writer = this;
this.inputPaths.forEach(function(inputPath) {
walkSync(inputPath).forEach(function(relativePath) {
if (relativePath.slice(-1) === '/') {
return;
}
var inFile = path.join(inputPath, relativePath);
var outFile = path.join(writer.outputPath, relativePath);
mkdirp.sync(path.dirname(outFile));
if (relativePath.slice(-3) === '.js' && !writer.excludes.match(relativePath)) {
writer.processFile(inFile, outFile, relativePath, writer.outputPath);
} else if (relativePath.slice(-4) === '.map') {
if (writer.excludes.match(relativePath.slice(0, -4) + '.js')) {
// ensure .map files for excldue JS paths are also copied forward
symlinkOrCopy.sync(inFile, outFile);
}
// skip, because it will get handled when its corresponding JS does
} else {
symlinkOrCopy.sync(inFile, outFile);
}
});
});
return this.outputPath;
};
UglifyWriter.prototype.enableSourcemaps = function() {
return this.sourceMapConfig.enabled &&
this.sourceMapConfig.extensions.indexOf('js') > -1;
};
UglifyWriter.prototype.mapURL = function(mapName) {
if (this.enableSourcemaps()) {
if (this.sourceMapConfig.mapDir) {
return '/' + path.join(this.sourceMapConfig.mapDir, mapName);
} else {
return mapName;
}
}
};
UglifyWriter.prototype.processFile = function(inFile, outFile, relativePath, outDir) {
var src = fs.readFileSync(inFile, 'utf-8');
var mapName = path.basename(outFile).replace(/\.js$/,'') + '.map';
var mapDir;
var origSourcesContent;
if (this.sourceMapConfig.mapDir) {
mapDir = path.join(outDir, this.sourceMapConfig.mapDir);
} else {
mapDir = path.dirname(path.join(outDir, relativePath));
}
var opts = {
fromString: true,
outSourceMap: this.mapURL(mapName),
enableSourcemaps: this.enableSourcemaps()
};
if (opts.enableSourcemaps && srcURL.existsIn(src)) {
var url = srcURL.getFrom(src);
opts.inSourceMap = path.join(path.dirname(inFile), url);
origSourcesContent = JSON.parse(fs.readFileSync(opts.inSourceMap)).sourcesContent;
}
try {
var start = new Date();
debug('[starting]: %s %dKB', relativePath, (src.length / 1000));
var result = UglifyJS.minify(src, merge(opts, this.options));
var end = new Date();
var total = end - start;
debug('[finished]: %s %dKB in %dms', relativePath, (result.code.length / 1000), total);
if (total > 20000 && process.argv.indexOf('--silent') === -1) {
console.warn('[WARN] (broccoli-uglify-sourcemap) Minifying: `' + relativePath + '` took: ' + total + 'ms (more than 20,000ms)');
}
} catch(e) {
e.filename = relativePath;
throw e;
}
if (opts.enableSourcemaps) {
var newSourceMap = JSON.parse(result.map);
// uglify is wrong about this and always puts the maps own name
// here.
newSourceMap.file = path.basename(inFile);
newSourceMap.sources = newSourceMap.sources.map(function(path){
// If out output file has the same name as one of our original
// sources, they will shadow eachother in Dev Tools. So instead we
// alter the reference to the upstream file.
if (path === relativePath) {
path = path.replace(/\.js$/, '-orig.js');
}
return path;
});
mkdirp.sync(mapDir);
fs.writeFileSync(path.join(mapDir, mapName), JSON.stringify(newSourceMap));
}
fs.writeFileSync(outFile, result.code);
};