SourceMap 原理
一、认识
1.1 bundle.js
通过打包工具, 打包出来的 bundle.js
文件最底部有一行:
// 省略其他代码...
//# sourceMappingURL=index-Cm-P-61P.js.map
这个就是记录原始代码与经过工程化处理代码之间位置映射关系 Map
文件,一切的秘密都在这里。
1.2 bundle.map
我们用简单一点代码来看下.map
里的内容结构:
{
"version": 3, // SourceMap 版本
"file": "index-Cm-P-61P.js", // 对应编译产物文件名
"sources": [ // 原始文件路径名,与 sourcesContent 内容一一对应
"../index.js"
],
"sourcesContent": [ // 原始代码内容
"const a = 1;\nconsole.log(a);\n\nconst array = [1, 2, 3, 4, 5];\n\narray.forEach((value, key) => {\n console.log(\"key\", key);\n console.log(\"value\", value);\n});\n\nfunction foo() {\n console.log(\"foo\");\n}\n\nfoo();\n"
],
"names": [ // 原始代码中出现的变量,用于 minify 的场景
"array",
"value",
"key",
"foo"
],
"mappings": "AACA,QAAQ,IAAI,CAAC,EAEb,MAAMA,EAAQ,CAAC,EAAG,EAAG,EAAG,EAAG,CAAC,EAE5BA,EAAM,QAAQ,CAACC,EAAOC,IAAQ,CAC5B,QAAQ,IAAI,MAAOA,CAAG,EACtB,QAAQ,IAAI,QAASD,CAAK,CAC5B,CAAC,EAED,SAASE,GAAM,CACb,QAAQ,IAAI,KAAK,CACnB,CAEAA,EAAK" // 记录打包产物与原始代码的映射关系
}
二、要素
2.1 mappings
mappings
记录打包产物与原始代码的映射关系, 主要有三部分组成:
-
line
: 以;
分割出的行映射。每个mapping
包含由;
分割的多行内容。其中每一行都对应生成代码的每行文件的位置映射信息,这里的三行分别对应了编译产物的三行信息 -
segment
: 以,
分割出代码中的片段(位置)映射。每一行同包含由,
分割的多个segment
信息,其中每个segment
都对应了产物里每一行里每一个符合所在的列的信息。比如"AAAA,IAAM,GAAG,GAAG,UAAC,CAAQ,EAAC,CAAQ;IAC5B,OAAO,CAAC,GAAC,CAAC,CAAC;AACb,CAAC,CAAA"
-
fields
: 代码片段, 每个segment
实际上又包含了几个field
,每个field
都编码了具体的行列映射信息。每个位置最多由5
位field
组成,依次为:-
第一位: 表示该片段在(转换后的代码的)的第几列。转换后代码所处的列号,如果这是当前行的第一个
segment
,那么是个绝对值,否则是相对于上一个segment
的相对值 -
第二位: 表示这个片段属于
sources
属性中的哪一个文件 (sources
数组的下标)。表示这个位置属于sources
属性中的哪一个文件,相对于前一个segment
的位置(区别于列号,下一行的第一个segment
仍然是相对于上一行的最后一个segment
,并不会reset
) -
第三位: 表示这个片段属于转换前代码的第几行。表示这个位置属于转换前代码的第几行,相对位置,同第二列
-
第四位: 表示这个片段属于转换前代码的第几列。表示这个位置属于转换前代码的第几列,相对位置,同第二列
-
第五位: 表示这个片段属于
names
属性中的哪一个变量。表示这个位置属于names
属性中的哪一个变量,相对位置,同第二列
-
这里 field
片段(位置) 存储映射的值并非是直接的数字值, 而是用到了一种比较高效数值编码算法 —— VLQ
(Variable-length Quantity
)编码。
根据上述这些信息我们实际上就可以实现 SourceMap
的双向映射了,即可以根据 SourceMap
和原始代码的位置信息查找到生成代码的信息,也可以根据 SourceMap
和生成代码的位置信息,查找到原始代码的信息。
三、VLQ 编码
3.1 Sourcemap 为什么会用到 VLQ 编码?
SourceMap
为了节省空间, 所以引入 VLQ
编码, 优化了.map
文件的大小,使得.map
文件更加紧凑和高效。