前言
JS代码发布到生产环境一般需要经过压缩混淆文件合并来减少体积和HTTP请求,而且我们现在使用TS开发,需要经过编译成JS代码。
这样得到的代码debug或者分析线上错误会比较困难。
这时候就需要SourceMap来协助解决了。
什么是Source map
Sourcemap是一个存储位置信息的文件。文件里霸气村的是转换后的代码位置和对应的转换前的位置。
这样在浏览器的调试工具里就可以直接看到原始代码,而不是转换后的代码了。
转换后的代码
转换前的代码
浏览器中如何启用sourcemap
在压缩代码的最后一行,加上这个引用,浏览器便会自动启动sourcemap。
1 | //# sourceMappingURL=app.js.map |
wenpack中如何配置生成sourcemap
在Vue-cli中可以默认在production环境下是生成sourcemap的,所有如果配置中有这句话,注释掉就可以了。
在其他模式下可以这样设置
1 | module.exports = { |
Source Map 格式
SourceMap的格式如下, 整个文件是一个json文件。
1 | { |
mappings属性
两个文件的位置是如何对应起来的。
关键就是mappings属性,它分为3层。
- 每个分号对应转换后源码的一行。
- 每个逗号对应转换后源码的一个位置。
- 每一段(aACE)以VLQ编码标识,代表该位置转换前的源码位置
以这个为例
1 | "mappings": "EAAcJ,EAAK,GACnBK,EAAiBL;EAAK,GAIHM,EAAI;" |
标识转换后的源码有两行,第一行有3个位置,第二行有两个位置。
位置对应的原理
每个位置用5位标识
- 第一位,表示这个位置在转换后代码第几列
- 第二位,表示这个位置属于sources属性中的哪一个文件
- 第三位,表示这个位置属于转换前的代码第几行
- 第四位,表示这个位置属于转换前的代码第几列
- 第五位,表示这个位置属于names属性的的哪一个变量
需要注意的是
- 所有值都是以0作为基数
- 第五位不是必须的,如果该位置没有对应names属性中的变量,第五位可以省略
- 每一位都采用VLQ编码表示, 由于VLQ编码是变长的,所以每一位可以由多个字符构成
比如某个位置是AAAAA,name表示这个位置的5个位实际上都是0。意思是,该位置在转换后的代码的第0列,对应的souces属性中的第0个文件,属于转换前代码的第0行第0列,对应names属性中的第0个变量。
Base64 VLQ编码
VLQ是Variable-length quantity 的缩写,是一种通用的、使用任意位数的二进制来表示一个任意大的数字的一种编码方式。
它的特点就是可以非常精简地表示很大的数值。
对16进行VLQ编码
- 将16改写成二进制形式10000
- 在最右边补充符号位。因为16大于0,所以符号位为0,整个数变成100000。
- 从右边的最低位开始,将整个数每隔5位,进行分段,即变成1和00000两段。如果最高位所在的段不足5位,则前面补0,因此两段变成00001和00000。
- 将两段的顺序倒过来,即00000和00001。
- 在每一段的最前面添加一个”连续位”,除了最后一段为0,其他都为1,即变成100000和000001。
- 将每一段转成Base 64编码。
- 查表 数值16的VLQ编码为gB。
步骤 | 结果 |
---|---|
将16改写成二进制形式 | 10000 |
16大于0,末尾符号位补0 | 100000 |
五位一组做分组,不足的补0 | 00001 00000 |
将组倒序排序 | 00000 00001 |
最后一组开头补0,其余补1 | 100000 000001 |
转64进制 | gB |
如何利用SourceMap 还原异常部分的源码
比如报错信息如下
1 | { |
Firefox 开源一个 source-map 的包,可以利用这个来还原代码
1 | const sourceMap = require('source-map') |
这样就可以还原到原来的代码,然后可以展示出附近的行数