1. 什么是source map ?
根据名字可以推测出source map就是我们编译后的源文件映射。当使用webpack 编译前端项目时,配置项devtool控制是否生成source map。
2. 分类
source map 文件可分为2类,内联型和外联(独立)型:
- 内联源映射,将映射的数据之间添加在生成的文件中,在.map文件中的‘sourcesContent’字段来存放源码
- 外联源映射,将映射数据存储在单独的映射文件中,使用标记将源链接到源码,一般会去掉源码中的注释
3. 关键字与模式
webpack为source map 提供了5个关键字eval,source-map,cheap,module,inline;以及从关键字衍生出来的7种不同模式。
5个关键字的含义见下表:
eval | 使用eval包裹模块代码 |
source-map | 生成.map文件 |
cheap | 不包含列信息,也不包含loader的sourcemap |
module | 包含loader的的sourcemap |
inline | 将.map作为DataURI嵌入,不单独生成.map文件 |
webpack配置文件中由上面几个关键字衍生出来的debtool7中模式如下表格:
模式 | 含义 | 类型 |
eval | 生成的代码每个模块都被eval执行,并且存在//@sourceURL | 内联 |
cheap-eval-source-map | 只包含行数据而不包含列映射。 | 内联 |
eval-source-map | 每个module会通过eval()来执行,并且生成一个DataUrl形式的SourceMap,比较慢。 | 内联 |
hidden-source-map | 和 source-map 一样,但不会在 bundle 末尾追加注释。 | 外联 |
cheap-source-map | 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用 | 外联 |
cheap-module-source-map | 生成一个没有列信息(column-mappings)的SourceMaps文件,同时 loader 的 sourcemap 也被简化为只包含对应行的。 | 外联 |
source-map | 原始代码最好的sourcemap质量有完整的结果,但速度是最慢的。 | 外联 |
3. eval模式
使用eval将webpack中每个模块包裹,然后在模块末尾添加模块来源//# souceURL, 依靠souceURL找到原始代码的位置。包含eval关键字的配置项并不单独产生.map文件,依靠sourceURL来定位原始代码。
4. source-map模式
都会产生一个.map文件,该文件保存有原始代码与运行代码的映射关系, 浏览器可以通过它找到原始代码的位置。(注:包含inline关键字的配置项也会产生.map文件,但是这个map文件是经过base64编码作为DataURI嵌入)。使用.map文件的方式来定位。
举个栗子:eval-source-map是eval和source-map的组合,可知使用eavl语句包括模块,也产生了.map文件。webpack将.map文件作为DataURI替换eval模式中末尾的//# souceURL。
5. source map文件格式
Source map文件的基本格式如下:
- version:Source map的版本,目前为3。
- file:转换后的文件名。
- sourceRoot:转换前的文件所在的目录。如果与转换前的文件在同一目录,该项为空。
- sources:转换前的文件。该项是一个数组,表示可能存在多个文件合并。
- names:转换前的所有变量名和属性名。
- mappings:记录位置信息的字符串,下文详细介绍。
mappings属性:
关键就是map文件的mappings属性。这是一个很长的字符串,它分成三层。
第一层是行对应,以分号(;)表示,每个分号对应转换后源码的一行。所以,第一个分号前的内容,就对应源码的第一行,以此类推。
第二层是位置对应,以逗号(,)表示,每个逗号对应转换后源码的一个位置。所以,第一个逗号前的内容,就对应该行源码的第一个位置,以此类推。
第三层是位置转换,以VLQ编码表示,代表该位置对应的转换前的源码位置。
有错误之处,欢迎指正。
参考资料: