source map的深入理解
- 为什么要使用
sourceMap
? -
sourceMap
如何实现资源定位?
1、sourceMap
为了让资源更小,加载速度更快,在js
项目部署之前都会将代码混淆压缩。但是这样也带来了影响,当代码中出现问题时,只能定位到压缩之后的代码。而压缩之后的代码一般就只有一两行,每一行上万字符,对排除检查几乎没有帮助。而sourceMap
的存在就是为了解决这个问题,它帮助将压缩的代码复原到源文件之中。
Source map
就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。
{
version : 3,
file: "out.js",
sourceRoot : "",
sources: ["foo.js", "bar.js"],
names: ["src", "maps", "are", "fun"],
mappings: "AAgBC,SAAQ,CAAEA"
}
- version:
source map
的版本 - file: 生成的文件
- sourceRoot: 源文件根目录
- sources: 源文件
- names: 源文件中变量、方法名
- mappings: 映射字符串,文件最核心部分,
2、如何转换?(Base64 VLQ的解码过程)
如何只单纯的记录原文件的所在行、所在列、所在具体位置,那么生成的source map
文件将是源文件的十倍之多,而现在一般的大小并没有那么吓人。而这主要使用了一种叫VLQ(variable-length-quantity)的编码方式。
基础补充:
Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。由于2^6=64,所以每6个比特为一个单元,对应某个可打印字符。
Base64
编码是将文本先ASCII编码,然后二进制转化,再讲二进制数每6个一位,不足的用0补充,接着映射到对应的字符。
sourceMap中的VLQ:
A single base 64 digit can contain 6 bits of data. For the base 64 variable length quantities we use in the source map spec, the first bit is the sign, the next four bits are the actual value, and the 6th bit is the continuation bit. The continuation bit tells us whether there are more digits in this value following this digit.
Continuation
| Sign
| |
V V
101011
上面是sourceMap源码中的一段注释。解释了,base64
每单位(6Bit)最高位(左侧第一位)表示是否连续,即如果是1表示后面的6位跟当前这6位为同一个数字;而最低位为符号位。所以实际表示大小的只有中间4位,所以每单位只能表示-15~+15的值。超过这个值得话就需要两个6位表示了。
Base64 VLG 编码:
比如: 10 -> K
16 -> 10000 -> 100000(大于0的符号位) -> 00001 00000(每五位分割) -> 00000 00001 (little-endian从低到高) -> 100000 000001(最后一组最高位为0 其他都是1 表连续) -> 32 1 -> gB
Base64 VLG 解码:
A -> 0
A -> 0
g -> 32
B -> 1
C -> 2
所以AAgBC -> 0 0 32 1 2 -> 0 0 16 2
根据下面的每一位具体含义比对,就能得到含义: 该位置在转换后代码的第0列,对应sources属性中第0个文件,属于转换前代码的第16行第2列
- 第一位,表示这个位置在(转换后的代码的)的第几列。
- 第二位,表示这个位置属于sources属性中的哪一个文件。
- 第三位,表示这个位置属于转换前代码的第几行。
- 第四位,表示这个位置属于转换前代码的第几列。
- 第五位,表示这个位置属于names属性中的哪一个变量。
参考资料:
introduction to JavaScript Source Maps
Base64
Variable-length_quantity
JavaScript Source Map 详解