背景
前端代码都是打包上线的,一旦出现错误很难判断具体发生在什么位置。但是source-map可以很好的帮助我们做代码反解。
实现思路
window.onerror = function (msg, url, row, col, error) {}
SDK监控到出现错误的地方进行上报。上报字段至少包含msg、url、row、col。 前端检测到异常告警时可以查到哪个资源的报错。当知道报错的资源以及row和col时,去服务端查询源码map文件,返回给客户端。
const sourceMap = require('source-map');
function lookupSourceMap(mapFile, line, column, callback) {
// 首先得知道map源文件,读文件
// 出错行 出错列 回调
fs.readFile(mapFile, function(err, data) {
if(err) {
console.error(err);
return;
}
// 源文件fileContent
let fileContent = data.toString(),
fileObj = JSON.parse(fileContent),
sources = fileObj.sources;
sources.map(item => {
sourcesPathMap[fixPath(item)] = item;
});
// console.log(sourcesPathMap, 'sourcesPathMap处理后');
const consumer = new sourceMap.SourceMapConsumer(fileContent);
console.log(consumer, 'consumer');
const lookup = {
line: parseInt(line),
column: parseInt(column)
};
console.log(lookup, 'lookup');
const result = consumer.originalPositionFor(lookup);
console.log(result, '查找result');
let originSource = sourcesPathMap[result.source],
sourcesContent = fileObj.sourcesContent[sources.indexOf(originSource)];
result.sourcesContent = sourcesContent;
// console.log(result, 'result');
callback && callback(result);
});
}
前端拿到解析到的源码文件进行处理。
const $errCode = document.getElementById('errCode');
$errCode.innerHTML = data.file;
const lines = $errCode.innerText.split('\n');
const row = data.row,
len = lines.length - 1;
const start = row - 3 >= 0? row - 3: 0,
end = start + 5 >= len? len: start + 5; // 最多展示6行
const newLines = [];
for(let i = start; i <= end; i++) {
newLines.push('<div class="code-line '+ (i + 1 == row? 'heightlight': '')+'" title="'+ (i + 1 === row ? encodeHTML(data.msg): '')+'">' + (i+1) + '. ' + encodeHTML(lines[i]) + '</div>');
}
target.innerHTML += '<div class="errdetail"><div class="errheader">' + data.source + ' at line ' + data.row + ':' + data.column + '</div>' +
'<pre class="errCode">' + newLines.join("") + '</pre></div>';