Skip to content
This repository has been archived by the owner on Oct 9, 2020. It is now read-only.

Support inline source maps #82

Merged
merged 11 commits into from
Feb 20, 2015
2 changes: 1 addition & 1 deletion compilers/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ exports.compile = function(load, opts, loader) {

if (opts.sourceMaps)
options.sourceMaps = 'memory';
if (opts.lowResolutionSourceMaps)
if (opts.lowResSourceMaps)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

options.lowResolutionSourceMap = true;

if (load.metadata.sourceMap)
Expand Down
37 changes: 19 additions & 18 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@ var builder = require('./lib/builder');

var path = require('path');

/* Very basic, null-friendly, shallow clone for object attributes only */
function clone(obj) {
obj = obj || {};
var copy = {};
for (var key in obj) {
copy[key] = obj[key];
function processOpts(opts_, outFile) {
var opts = {
config: {},
lowResSourceMaps: false,
minify: false,
normalize: false,
outFile: outFile,
runtime: false,
sourceMaps: false,
sourceMapContents: opts_ && opts_.sourceMaps == 'inline'
};
for (var key in opts_) {
if (key in opts)
opts[key] = opts_[key];
}
return copy;
return opts;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be really nice to the engine, let's make this function define all the properties on opts that need to be used. This way it can be optimized by a single class without hitting deoptimizations later. It also acts nicely as a simple centralisation of info when I forget what all the options do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure


function Builder(cfg) {
Expand Down Expand Up @@ -201,9 +209,7 @@ function buildOutputs(loader, tree, opts, sfxCompilers) {

Builder.prototype.buildTree = function(tree, outFile, opts) {
var loader = this.loader;

opts = clone(opts);
opts.outFile = outFile;
opts = processOpts(opts, outFile);

return buildOutputs(loader, tree, opts, false)
.then(function(outputs) {
Expand All @@ -214,17 +220,12 @@ Builder.prototype.buildTree = function(tree, outFile, opts) {

Builder.prototype.buildSFX = function(moduleName, outFile, opts) {
var loader = this.loader;

opts = clone(opts);
opts.outFile = outFile;

var config = opts.config;
opts = processOpts(opts, outFile);
opts.normalize = true;

var outputs;

var compilers = {};
opts.normalize = true;
return this.trace(moduleName, config)
return this.trace(moduleName, opts.config)
.then(function(trace) {
moduleName = trace.moduleName;
return buildOutputs(loader, trace.tree, opts, compilers);
Expand Down
26 changes: 17 additions & 9 deletions lib/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,16 @@ function processOutputs(outputs) {
return outputObj;
}

function createOutput(outputs, outFile, baseURL, createSourceMaps) {
function createOutput(outputs, outFile, baseURL, opts) {
// process output
var sourceMap;

var outputObj = processOutputs(outputs);

if (createSourceMaps && outputObj.sourceMapsWithOffsets.length) {
if (opts.sourceMaps && outputObj.sourceMapsWithOffsets.length) {
var sourceRoot = outFile ? path.dirname(baseURL + outFile) + path.sep : baseURL;
sourceMap = saucy.concatenateSourceMaps(outFile, outputObj.sourceMapsWithOffsets, sourceRoot);
var mapsWithOffsets = outputObj.sourceMapsWithOffsets;
sourceMap = saucy.concatenateSourceMaps(outFile, mapsWithOffsets, sourceRoot, opts.sourceMapContents);
}

var output = outputObj.sources.join('\n');
Expand Down Expand Up @@ -105,14 +106,15 @@ function minify(output, fileName, mangle) {
}

function writeOutputFile(opts, output, basePath) {
if (opts.sourceMaps) {
var sourceMapFile = path.basename(opts.outFile) + '.map';
var sourceMapFile;
if (opts.sourceMaps && output.sourceMap) {
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;
if (!output.sourceMap || !opts.sourceMaps) return;
var sourceMapPath = path.resolve(basePath, path.dirname(opts.outFile), sourceMapFile);
return asp(fs.writeFile)(sourceMapPath, output.sourceMap);
})
Expand All @@ -122,11 +124,12 @@ function writeOutputFile(opts, output, basePath) {
});
}

exports.inlineSourceMap = function(output) {
exports.inlineSourceMap = inlineSourceMap;
function inlineSourceMap (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
Expand All @@ -135,11 +138,16 @@ exports.writeOutput = function(opts, outputs, baseURL) {
if (opts.outFile)
opts.outFile = path.relative(basePath, path.resolve(opts.outFile));

var output = createOutput(outputs, opts.outFile, baseURL, opts.sourceMaps);
var output = createOutput(outputs, opts.outFile, baseURL, opts);

if (opts.minify)
output = minify(output, opts.outFile, opts.mangle);

if (opts.sourceMaps == 'inline') {
output.source = inlineSourceMap(output);
output.sourceMap = undefined;
}

if (opts.outFile)
return writeOutputFile(opts, output, basePath).then(function() { return output; });
else
Expand Down
7 changes: 6 additions & 1 deletion lib/sourcemaps.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ function getMapObject(map) {
}
}

exports.concatenateSourceMaps = function(sourceFilename, mapsWithOffsets, sourceRoot) {
exports.concatenateSourceMaps = function(sourceFilename, mapsWithOffsets, sourceRoot, includeSourcesContent) {
if (includeSourcesContent) {
console.log('WARNING: `includeSourcesContent` not support yet, ' +
'see https://github.com/systemjs/builder/issues/68');
}

var generated = new sourceMap.SourceMapGenerator({
file: sourceFilename
});
Expand Down
27 changes: 27 additions & 0 deletions test/unit-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ var fs = require('fs');
var Builder = require('../index');
var assert = require('chai').assert;

function atob(str) {
return new Buffer(str, 'base64').toString('binary');
}

var err = function(e) {
setTimeout(function() {
throw e;
Expand Down Expand Up @@ -49,6 +53,29 @@ writeTestOutput();

describe('Source Maps', function() {

it('can render inline', function(done) {
var module = 'tree/amd-2';
var filename = 'inline-source-map.js';

var instance = new Builder('./test/cfg.js');
instance.build(module, null, { sourceMaps: 'inline' })
.then(function(output) {
assert.equal(undefined, output.sourceMap);
var source = output.source;
assert.equal(1, source.match(/sourceMappingURL=/g).length);
var lines = output.source.split("\n");
var lastLine = lines[lines.length - 1];
var commentPrefix = /^\/\/# sourceMappingURL=data:application\/json;base64,/;
assert(lastLine.match(commentPrefix));
var encoding = lastLine.replace(commentPrefix, "");
var decoded = JSON.parse(atob(encoding));
// not a regular array so tedious
assert.equal(1, decoded.sources.length);
assert.equal('tree/amd-2.js', decoded.sources[0]);
done();
});
});

describe('sources paths', function() {

var getSources = function(map) {
Expand Down