This repository demonstrates a common problem where webpack loaders are responsible for broken source maps. You will notice broken source maps by jumping break points when you're trying to debug your application.
A simple implementation of a webpack loader could generate additional JavaScript like this:
function brokenLoader(content, sourceMap) {
// Don't do this since it makes the sourceMap information useless :(
const newContent = "// this is some content which will offset the source map by one line\n" + content;
this.callback(null, newContent, sourceMap);
}
The problem is that the mappings from the received sourceMap
will not match the generated content anymore.
You can see the problem in this example.
Scroll down until you see console.log("Hello world");
and hover over it. You'll see that the mapping between the generated code and the original source code is not correct.
Use the source-map
module if you need to pre- or append strings.
Unfortunately, the API is not straight-forward to use. This is the boilerplate code to fix the problem from above:
const prefix = "// this is some content which will offset the source map by one line\n";
// Either create a SourceNode instance from scratch or based on an input sourceMap
async function createSourceNode(resourcePath, content, sourceMap) {
if (sourceMap === undefined) {
const node = new SourceNode(1, 0, resourcePath, content);
node.setSourceContent(resourcePath, content);
return node;
}
return SourceMapConsumer.with(sourceMap, null, consumer =>
SourceNode.fromStringWithSourceMap(content, consumer)
);
}
async function fixedLoader(content, sourceMap) {
if (!this.sourceMap) {
// If we don't care about source maps, we can just do whatever we want.
return prefix + content;
}
this.async();
const node = await createSourceNode(this.resourcePath, content, sourceMap);
node.prepend(
// In our case, the generated loader code cannot be mapped to the original source code
// so let's prepend some code without any mappings to original line and column numbers.
new SourceNode(
null, // null = no original line number
null, // null = no original column number
null, // null = no original source file
prefix
)
);
const { code, map: mapGenerator } = node.toStringWithSourceMap();
// JSON.parse(mapGenerator.toString()) is kind of stupid but that's
// the way how the source-map module works. Maybe since maps are generated by WASM?
const map = JSON.parse(mapGenerator.toString());
this.callback(null, code, map);
}
Take a look at the new output. The generated mapping is correct now.
source-map-visualization is an excellent tool to debug and validate the generated source maps. The source-map
module also provides a way to query row and column mappings which you should do in your loader test suite to verify that the source maps are correct.