Apply source maps to profiles
What is the problem this feature will solve?
When debugging bundled/compiled/minified code, it's difficult to read a profile as locations and many function names point to the compiled code.
What is the feature you are proposing to solve the problem?
Apply source maps to profiles (perhaps when --enable-source-maps is passed).
What alternatives have you considered?
post-augmentation (via the source-map package), or other tools (such as speedscope) which claim to be able to apply sourcemaps (but dont always work).
There has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the https://github.com/nodejs/node/labels/never-stale label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document.
maintainers: can we get some sort of signal here so that this issue doesn't stay open unnecessarily?
@mbrevda, I'm having similar a issue did you find any workarounds or post augmentation tools for this?
Here's a script I'm using to augment post profile
import {readFile} from 'fs/promises';
import {SourceMapConsumer} from 'source-map';
import {join} from 'path';
const sourceMap = {};
const loadSourceMap = async (codePath, filepath) => {
const sourceFile = await readFile(codePath + '/' + filepath, 'utf-8');
const mapFileUrlLine = sourceFile
.split('\n')
.reverse()
.find((line) => line.startsWith('//# sourceMappingURL='));
if (!mapFileUrlLine) {
console.warning('could not find sourceMappingURL line for', filepath);
return false;
}
const mapFileUrl = mapFileUrlLine.replace('//# sourceMappingURL=', '');
const mapFile = await readFile(codePath + '/' + mapFileUrl, 'utf-8');
if (!mapFile) {
console.warning(`could not find source map file ${mapFile} for`, filepath);
return false;
}
return await new SourceMapConsumer(mapFile);
};
const remapProfile = async (projectDir, trace) => {
const codePath = projectDir + '/dist';
const mappedNodes = [];
for (const [index, node] of trace.nodes.entries()) {
mappedNodes.push(node);
const {url, lineNumber, columnNumber, functionName} = node.callFrame;
if (!url || !lineNumber) continue;
const {protocol, pathname} = new URL(url);
if (!pathname.startsWith(codePath)) continue;
const filepath = pathname.replace(codePath + '/', '');
if (sourceMap[filepath] === false) continue; // we already tried to load this source map and failed
if (!(filepath in sourceMap)) {
sourceMap[filepath] = await loadSourceMap(codePath, filepath);
}
if (!sourceMap[filepath]) continue;
const {source, line, column, name} = sourceMap[
filepath
].originalPositionFor({
line: lineNumber,
column: columnNumber,
});
if (!source && !line && !column && !name) continue;
const mappedUrl = source ? `${protocol}//` + join(codePath, source) : url;
// use original function name if available
let mappedFunctionName = functionName;
if (name) {
// if we have a name, but no function name, use the name
if (!functionName) {
mappedFunctionName = name;
} else {
// if we have both, use both
mappedFunctionName = `${name} (${functionName})`;
}
}
mappedNodes[index] = {
...mappedNodes[index],
callFrame: {
...(mappedNodes[index]?.callFrame || {}),
url: mappedUrl,
lineNumber: line,
columnNumber: column,
functionName: mappedFunctionName,
},
};
}
return {...trace, nodes: mappedNodes};
};
export default async (projectDir, profile) => {
return await remapProfile(projectDir, profile);
};
There has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the https://github.com/nodejs/node/labels/never-stale label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document.
I think this is important and should be kept open until implemented.