深入理解SourceMap原理及应用

2,342 阅读5分钟

1. 什么是SourceMap

通常来说,现在我们使用Vue,React等 开发前端应用,都需要通过webpack来对文件进行编译和处理,如果发布到线上的话,还需要对编译之后的代码进行混淆,压缩等处理,已达到优化用户体验的目的,这个时候就涉及到了一个问题。压缩后的代码通常是以一行或者多行的形式出现,不利于我们直接定位线上的问题。这个时候SourceMap就应运而生了。

按照我的理解:

SourceMap的作用是保存压缩处理后的代码与源码之间的映射关系

我们直接对下面的代码进行编译:

console.log("test")

编译出来的结果是:

{ "version": 3, "file": "main.js", "mappings": "AAAAA,QAAQC,IAAI", "sources": ["webpack://webpack-sourcemap-demo/./index.js"], "sourcesContent": ["console.log(\"test\")"], "names": ["console", "log"], "sourceRoot": "" }

各个字段表达的含义:

version: 代表sourceMap的版本

file: 代表生成后的代码名称

sources: 代表源文件名称

sourcesContent: 存放源代码内容的数组

names: 存放转换前变量和属性

mappings: 表示了源代码及编译后代码的关系

2. Base VLQ原理

上面所说的mappings就是使用了Base VLQ编码的形式

Base VLQ 顾名思义是由Base 64 + VLQ 编码方式来构成的

现在把1024用base64-vql编码方式表示

1、首先我们把1024转化为二进制——1 00000 00000,一共11位;

图1 2、在最右边补充符号位,因为1024是正数,所以最右边补充一个0——10 00000 00000,此时一共12位;

3、现在从最右边向左边每隔5位划分为一组,不足五位的左边补充0——00010 00000 00000,一共15位;

4、将组的位置顺序颠倒一下——00000 00000 00010;

5、在最左边为每组补充一位,如果这组是这个数值的最后一组,那么就补充0,前面的组都补充1——100000 100000 000010(32 32 2),一共18位

最后通过 Base 64 编码表来对应到最终的结果: ggc

拓展:

  1. Base 64编码:简单来说就是将二进制编码转化成为可见的ASC II 可见编码的过程,在日常中Base 64编码有着举足轻重的意义,主要用于无损的传输二进制(比如邮箱发送协议SMTP,SMTP为老旧的协议,不支富文本的传输,所以理论上是不支持图片的发送的,但是Base 64就解决了这个问题),将二进制编码成为可见的ASC II 然后接收端通过接收到的baes 64 还原为原来的二进制数据

  2. VLQ 编码:VLQ 编码的意义在于将数组转化成为字符串,简化了存储的数据结构,在SourceMap大量查找的情况下,提升了查找对应代码的性能

例如:mappings中是:AAgGA 对应编码前的数组为[0,0,96,0]

具体为什么提高了性能,不多做解释

数组代表的含义是:

第一位,表示这个位置在(转换后的代码的)的第几列。

第二位,表示这个位置属于sources属性中的哪一个文件。

第三位,表示这个位置属于转换前代码的第几行。

第四位,表示这个位置属于转换前代码的第几列。

第五位,表示这个位置属于names属性中的哪一个变量(可省略)。

base vlq编码的话,最后是通过Base 64进行编码的,也就是单个字符对应的数字最多也就只能到63(0代表一位),超过64的数字我们要怎样表示呢?

我们在转化成为二进制的时候,可以对其进行补位来表示是否将两个数字(或者以上的数字)用来表示一个数字,也就是在二进制数据前面增加0或者1来表示

VLQ转换网址

3. SourceMap分类

大致上SourceMap根据关键词可以分为这几类

关键词含义备注
source-map产生.map 文件最为常见的source-map
eval使用 eval 包裹模块代码能够缓存sourceMap
cheap不包含列信息也不包含 loader 的 sourcemap1. 只能定位到行,没有列信息无法定位到列 2. 经过babel转化之后,只能定位到转换前的代码
module包含 loader 的 sourcemap(比如 jsx to js ,babel 的 sourcemap),否则无法定义源文件解决对于使用``cheap 配置项导致无法定位到 loader 处理前的源代码问题
hidden隐藏sourceMappingURL线上使用,配合监控系统更佳
inline在原来source-map的基础上,将sourceMappingURL的文件改为.map文件的base 64内容

4. 理解SourceMap有什么用?

1. 能够在webpack中合理的选择SourceMap类型

在开发环境,我们的要求是:快,能够定位到源码的出错位置

所以一般来说选择:cheap-module-source-map

线上环境的话,我们是不能让使用者可以看到source-map的,所以使用hidden-source-map,配合前端监控系统

2. 在前端监控系统中使用

在线上定位出错未知的时候,需要我们把异常报错的位置传给后台,但是经过压缩和编译之后的代码是无法对应到源码位置的,所以需要我们在发布的时候,把.map文件传给监控系统,通过上错的报错位置结合source-map解析库 来定位到真实的报错位置

3. 拓展开发思维

明白了LVQ编码的意义和base 64 编码的意义能够加深对编码的理解