最近在开发一个低代码平台,主要用于运营搭建 H5 活动。这中间涉及到第三方组件的开发,而第三方组件想要接入平台,需要经过我们特定的打包工具来 build。构建之后的组件,会合并成单个的 js 文件,而且代码会被压缩会混淆,这个时候如果需要调试,那就会极其痛苦。想要有一个好的调试环境,就要涉及 SourceMap 的输出,而 Webpack 的 devtools
字段就是用于控制 SourceMap。
SourceMap 原理
在详细解释 devtools 配置之前,先看看 SourceMap 的原理。SourceMap 的主要作用就是用来还原代码,将已经编译压缩的代码,还原成之前的代码。
下图左边代码为 Webpack 打包之前,右边为打包之后。
![alt](https://i-blog.csdnimg.cn/blog_migrate/5d83d20e4e3e3da8c5a1749087f176c8.png)
打开 chrome 引入 dist.js
,会发现浏览器会自动将压缩的代码进行了还原。
![alt](https://i-blog.csdnimg.cn/blog_migrate/0d41bbd35b64789e34e983d94dfdaefe.png)
那这个 SourceMap 到底是怎么将右边的代码还原成左边的样子的呢。我们先看一下 dist.js.map
的结构。
{
// 版本号
"version": 3,
// 输出的文件名
"file": "dist.js",
// 输出代码与源代码的映射关系
"mappings": "MAAA,IAAMA,EAAM,CACVC,KAAM,KACNC,OAAQ,KAGV,SAASC,IACPH,EAAIE,QAAU,EAGhB,SAASE,IACPJ,EAAIE,QAAU,EACdG,QAAQC,IAAIN,EAAIC,KAAM,OAGxBE,IACAC,IACAA,IACAD,K",
// 原代码中的一些变量名
"names": [
"dog", "name", "weight",
"eat", "call", "console", "log"
],
// 源文件列表
// 我们打包的时候经常是多个js文件合并成一个,所以源文件有多个
"sources": [
"webpack:///./src/index.ts"
],
// 源文件内容的列表,与sources字段对应
"sourcesContent": [
"const dog = {\n name: '旺财',\n weight: 100\n}\n\nfunction eat() {\n dog.weight += 1\n}\n\nfunction call() {\n dog.weight -= 1\n console.log(dog.name, '汪汪汪')\n}\n\neat()\ncall()\ncall()\neat()"
],
}
其他字段应该都好理解,比较难懂的就是 mappings
字段,看着就像是一堆乱码。这是一串使用 VLQ 进行编码的字符串,规则比较复杂。我们可以直接在 github 找一个VLQ(https://github.com/Rich-Harris/vlq/blob/master/src/index.js)编码的库,对这串字符进行解码。
/** @type {Record<string, number>} */
let char_to_integer = {};
/** @type {Record<number, string>} */
let integer_to_char = {};
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
.split('')
.forEach(function (char, i) {
char_to_integer[char] = i;
integer_to_char[i] = char;
});
/** @param {string} string */
functi