Skip to content

Ensure source map can be resolved from cached code #662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions lib/caching-precompiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var cachingTransform = require('caching-transform');
var md5Hex = require('md5-hex');
var stripBom = require('strip-bom');
var objectAssign = require('object-assign');
var generateMapFileComment = require('convert-source-map').generateMapFileComment;

module.exports = CachingPrecompiler;

Expand Down Expand Up @@ -59,9 +60,22 @@ CachingPrecompiler.prototype._factory = function (babelConfig, cacheDir) {
code = code.toString();
var options = buildOptions(filename, code);
var result = babel.transform(code, options);
var mapFile = path.join(cacheDir, hash + '.map');
var mapFile = path.join(cacheDir, hash + '.js.map');
fs.writeFileSync(mapFile, JSON.stringify(result.map));
return result.code;

// When loading the test file, test workers intercept the require call and
// load the cached code instead. Libraries like nyc may also be intercepting
// require calls, however they won't know that different code was loaded.
// They may then attempt to resolve a source map from the original file
// location.
//
// Add a source map file comment to the cached code. The file path is
// relative from the directory of the original file to where the source map
// is cached. This will allow the source map to be resolved.
var sourceDir = path.dirname(filename);
var relMapFile = path.relative(sourceDir, mapFile);
var mapFileComment = generateMapFileComment(relMapFile);
return result.code + '\n' + mapFileComment;
};
};

Expand Down
2 changes: 1 addition & 1 deletion lib/test-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ installPrecompiler(function (filename) {
var precompiled = opts.precompiled[filename];

if (precompiled) {
sourceMapCache[filename] = path.join(cacheDir, precompiled + '.map');
sourceMapCache[filename] = path.join(cacheDir, precompiled + '.js.map');
return fs.readFileSync(path.join(cacheDir, precompiled + '.js'), 'utf8');
}

Expand Down
33 changes: 31 additions & 2 deletions test/caching-precompiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var uniqueTempDir = require('unique-temp-dir');
var sinon = require('sinon');
var babel = require('babel-core');
var transformRuntime = require('babel-plugin-transform-runtime');
var fromMapFileSource = require('convert-source-map').fromMapFileSource;

var CachingPrecompiler = require('../lib/caching-precompiler');

Expand All @@ -18,7 +19,7 @@ function endsWithJs(filename) {
}

function endsWithMap(filename) {
return /\.js$/.test(filename);
return /\.js\.map$/.test(filename);
}

sinon.spy(babel, 'transform');
Expand Down Expand Up @@ -50,7 +51,35 @@ test('adds files and source maps to the cache directory as needed', function (t)
var files = fs.readdirSync(tempDir);
t.is(files.length, 2);
t.is(files.filter(endsWithJs).length, 1, 'one .js file is saved to the cache');
t.is(files.filter(endsWithMap).length, 1, 'one .map file is saved to the cache');
t.is(files.filter(endsWithMap).length, 1, 'one .js.map file is saved to the cache');
t.end();
});

test('adds a map file comment to the cached files', function (t) {
var tempDir = uniqueTempDir();
var precompiler = new CachingPrecompiler(tempDir, null);

precompiler.precompileFile(fixture('es2015.js'));

var cachedCode;
var cachedMap;
fs.readdirSync(tempDir).map(function (file) {
return path.join(tempDir, file);
}).forEach(function (file) {
if (endsWithJs(file)) {
cachedCode = fs.readFileSync(file, 'utf8');
} else if (endsWithMap(file)) {
cachedMap = fs.readFileSync(file, 'utf8');
}
});

// This is comparable to how nyc resolves the source map. It has access to the
// cached code but believes it to come from the original es2015.js fixture.
// Ensure the cached map can be resolved from the cached code. Also see
// <https://github.com/bcoe/nyc/blob/69ed03b29c423c0fd7bd41f9dc8e7a3a68f7fe50/index.js#L244>.
var foundMap = fromMapFileSource(cachedCode, path.join(__dirname, 'fixture'));
t.ok(foundMap);
t.is(foundMap.toJSON(), cachedMap);
t.end();
});

Expand Down