systemjs-builder
Version:
SystemJS Build Tool ===
148 lines (123 loc) • 4.1 kB
JavaScript
var saucy = require('./sourcemaps');
var path = require('path');
var mkdirp = require('mkdirp');
var fs = require('fs');
var rsvp = require('rsvp');
var asp = rsvp.denodeify;
var uglify = require('uglify-js');
function countLines(str) {
return str.split(/\r\n|\r|\n/).length;
}
// Process compiler outputs, gathering:
//
// concatOutputs: list of source strings to concatenate
// sourceMapsWithOffsets: list of [absolute offset,
// source map string] pairs
//
// Takes lists as empty references and populates via push.
function processOutputs(outputs) {
var offset = 0;
var outputObj = {};
var sources = outputObj.sources = [];
var sourceMapsWithOffsets = outputObj.sourceMapsWithOffsets = [];
if (!outputs)
return outputObj;
outputs.forEach(function(output) {
var source;
if (typeof output == 'object') {
source = output.source || '';
var offset_ = output.sourceMapOffset || 0;
var map = output.sourceMap;
if (map) {
sourceMapsWithOffsets.push([offset + offset_, map]);
}
}
else if (typeof output == 'string') {
source = output;
}
else {
throw "Unexpected output format: " + output.toString();
}
source = saucy.removeSourceMaps(source || '');
offset += countLines(source);
sources.push(source);
});
return outputObj;
}
function createOutput(outputs, outFile, baseURL, createSourceMaps) {
// process output
var sourceMap;
var outputObj = processOutputs(outputs);
if (createSourceMaps && outputObj.sourceMapsWithOffsets.length) {
var sourceRoot = outFile ? path.dirname(baseURL + outFile) + path.sep : baseURL;
sourceMap = saucy.concatenateSourceMaps(outFile, outputObj.sourceMapsWithOffsets, sourceRoot);
}
var output = outputObj.sources.join('\n');
return {
source: output,
sourceMap: sourceMap
};
}
function minify(output, fileName, mangle) {
var ast = uglify.parse(output.source, { filename: fileName });
ast.figure_out_scope();
ast = ast.transform(uglify.Compressor({ warnings: false }));
ast.figure_out_scope();
ast.compute_char_frequency();
if (mangle !== false) {
ast.mangle_names({
except: ['require']
});
}
var sourceMap;
if (output.sourceMap)
sourceMap = uglify.SourceMap({
file: fileName,
orig: output.sourceMap
});
output.source = ast.print_to_string({
// for some reason non-ascii broke esprima.... this does break unicode though
ascii_only: true,
// keep first comment
comments: function(node, comment) {
return comment.line === 1 && comment.col === 0;
},
source_map: sourceMap
});
output.sourceMap = sourceMap;
return output;
}
function writeOutputFile(opts, output, basePath) {
if (opts.sourceMaps) {
var sourceMapFile = path.basename(opts.outFile) + '.map';
output.source += '\n//# sourceMappingURL=' + sourceMapFile;
}
return asp(mkdirp)(path.dirname(path.resolve(basePath, opts.outFile)))
.then(function() {
if (!opts.sourceMaps) return;
var sourceMapPath = path.resolve(basePath, path.dirname(opts.outFile), sourceMapFile);
return asp(fs.writeFile)(sourceMapPath, output.sourceMap);
})
.then(function() {
var sourcePath = path.resolve(basePath, opts.outFile);
return asp(fs.writeFile)(sourcePath, output.source);
});
}
exports.inlineSourceMap = function(output) {
return output.source +
'\n//# sourceMappingURL=data:application/json;base64,' +
new Buffer(output.sourceMap.toString()).toString('base64');
};
exports.writeOutput = function(opts, outputs, baseURL) {
// remove 'file:' part
var basePath = baseURL.substr(5);
if (opts.outFile)
opts.outFile = path.relative(basePath, path.resolve(opts.outFile));
var output = createOutput(outputs, opts.outFile, baseURL, opts.sourceMaps);
if (opts.minify)
output = minify(output, opts.outFile, opts.mangle);
if (opts.outFile)
return writeOutputFile(opts, output, basePath).then(function() { return output; });
else
return rsvp.resolve(output);
};