摘要: Source Map 还是很神奇的。
- 原文:线上出 bug 了?别怕,这么定位!
- 公众号:前端小苑
Fundebug 经授权转载并修改,版权归原作者所有。
工作中,生产环境代码是编译后代码,搜集到报错信息的行和列无法在源码中对应,很多时候只能靠“经验”去猜,本文针对这种情况,开发了一个 npm 命令行小工具,帮助快速定位报错的源码位置,提升效率。
由于现在构建工具盛行,前端部署的代码都是经过编译,压缩后的, 于是乎 ,SoueceMap 就扮演了一个十分重要的角色,用来作为源代码和编译代码之间的映射,方便定位问题。
测试 SourceMap 功能
首先全局安装 reverse-sourcemap
npm install --global reverse-sourcemap
选择编译后的代码进行测试,下面是 vue 项目编译生成的代码。
在命令行执行命令,将 main.js 反编译回源码,并输出到 sourcecode 目录下。
reverse-sourcemap -v dist/main.a8ebc11c3f03786d8e3b.js.map -o sourcecode
上面是执行命令输出的 sourcecode 目录,生成的目录结构和源码目录一致,打开一个文件,和源码做下对比:
可以看出,反编译出的代码无论目录结构还是具体代码都和源码一致。
生产环境代码报错如何定位源码位置
如果使用了 Fundebug 的 Source Map 功能的话,则可以很方便的定位出错位置:
如果没有使用监控工具的话,生产环境的代码,经过压缩、编译,很不利于 Debug。针对这个问题,需要准备一份生产环境代码的 map 文件,为了方便,可以在项目的 package.json 增加 debug 命令用来生成 map 文件。这条命令除了开启 sourcemap,其他的具体 webpack 配置和生产环境配置相同。
"scripts": {
"start": "vue-cli-service serve --mode dev",
"stage": "vue-cli-service build --mode staging",
"online": "vue-cli-service build",
"debug": "vue-cli-service build --mode debug"
}
有了 map 文件,通过 SourceMap 提供的 API 就可以定位到源码的位置。下面是实现的核心代码。
// Get file content
const sourceMap = require('source-map');
const readFile = function (filePath) {return new Promise(function (resolve, reject) {fs.readFile(filePath, {encoding:'utf-8'}, function(error, data) {if (error) {console.log(error)
return reject(error);
}
resolve(JSON.parse(data));
});
});
};
// Find the source location
async function searchSource(filePath, line, column) {const rawSourceMap = await readFile(filePath)
const consumer = await new sourceMap.SourceMapConsumer(rawSourceMap);
const res = consumer.originalPositionFor({
'line' : line,
'column' : column
});
consumer.destroy()
return res
}
最重要的就是使用 SourceMap 提供的 originalPositionFor API。SourceMapConsumer.prototype.originalPositionFor(generatedPosition)
originalPositionFor API 的参数为一个包含 line 和 column 属性的对象 line 编译生成代码的行号,从 1 开始
column 编译生成代码的列号,从 0 开始
这个方法会返回一个具有以下属性的对象
{
"source": "webpack:///src/pages/common/403.vue?c891", // 源代码文件的位置, 如果无法获取,返回 null。"line": 4, // 源代码的行号,从 1 开始,如果无法获取,返回 null。"column": 24, // 源代码的列号,从 0 开始,如果无法获取,返回 null。"name": "get" // 源代码的标识,如果无法获取,返回 null。}
源码定位工具
为了使用方便,我将这个功能做成了一个命令行小工具。全局安装后,不需要做任何配置就可以使用。
安装
npm install --global source-location
参数介绍
Usage: sl [options]
Options:
-v, --version output the version number
-p, --source-flie-path The generated source file 编译后的 map 文件
-l, --ine The line number in the generated source 编译后代码行号
-c, --column The column number in the generated source 编译后代码列号
-h, --help output usage information
使用案例
终端执行命令:
sl -p dist/1.f47efcb58028826c7c05.js.map -l 1 -c 34
命令行将会输出:源码的文件路径:path,源码行号:line,源码标识:name。
项目的 github 地址:github.com/front-end-y… 如有错误欢迎指出。
最后,推荐大家使用 Fundebug,一款很好用的 BUG 监控工具,支持 Source Map 功能~