Source Map详解

298 阅读4分钟

本文的主题:

  • 什么是source-map?

  • mappings属性解读

  • 如何使用source-map

  • devtool的配置和对应值的含义

什么是source-map

我们知道现在前端是工程化的时代,开发写过代码会经过一些列的操作:

  • 转译(babel,把es6/图片/css转成浏览器可以识别的代码)

  • 编译器 typescript

  • 压缩/Minifiers (UglifyJS)

经过这些操作以后我们的代码已经面目全非,但是我们又需要在开发或者线上的时候定位问题。此时就产生了source-map。souce-map就是生成一些map文件,这些文件能够记录源文件代码具体位置信息(记录的详细程度和配置有关)。

总结:源码映射,可以将编译压缩后的代码再对应回未压缩的源码。

文件解析

    生成的source-map生成的是json文件,其中字段有以下几个:

{
    "version":3,
    "file":"js/nosources-source-map/nosources-source-map.js",
    "mappings":"AAAAA,BBBBB;CCCCC",
    "sources":[
        "webpack://02_webpack_config_start/./src/index.js"
    ],
    "names":[
        "console",
        "log",
        "log1111"
    ],
    "sourceRoot":""
}

version: source-map的版本

file: 生成的map文件路径名称

sources: 源文件

names: 源文件转换的变量名和属性名

mappings:该字段是map文件的关键,存储产出文件files和源文件的对应关系

mappings属性解读

"mappings":"AAAAA,BBBBB;CCCCC"

mappings是记录的核心,这一对字母是什么意思呢?

mappings属性解读分三层属性:

    第一层是行对应,以分号(;)隔开,每个分号表示源码的一行。上面表示源代码有2行信息。

    第二层是位置对应,以逗号(,)隔开。比如,上面的AAAAA,BBBBB 中AAAA表示第一行的第一个变量或者属性,BBBB表示第一行的第二个变量。

    第三层是位置转换,每一个逗号表示一个位置信息,这些信息经过了BASE64 VLQ编码。

读到这里,那么问题又来了,

    第一:一个逗号表示一个基本的位置信息的话,存储了哪些位置信息呢?

    第二,BASE64 VLQ编码是什么意思?

第一个问题:

    记录了5位的信息(00150):

  • 第一位,表示在转换后的代码中的第几列。 

  • 第二位,表示该位置在sources中的哪一个文件,sources中的索引。

  • 第三位,表示在转换前文件的第几行

  • 第四位,表示在转换前文件的第几列

  • 第五位,表示names中的索引。

生成文件的列,源文件的索引,源文件行号,源文件列号,名称的索引

其中,源文件的索引,源文件的列号,名称的索引都是可以省略(devtool的配置不同可以不生成这些信息)。所以这是利用可变长度来表示的原因。

具体位置相关的设计思想参考该文章: Source Map的原理探究 ,这里不做深入探讨。

第二个问题:

    VLQ: Variable-length quantity

如何使用source-map

    生成source-map: 只需要在webpack中启用devtool功能即可

devtool: 'eval'

具体配置可以参考官网

基本类型:

eval: 源码会被eval函数包含

source-map: 会生成一个独立的map文件

cheap: 只关心文件的行号,不关心列号

inline: 生成的map数据以dataurl的方式注入到生成的文件中

//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianMvaW5saW5lLXNvdXJjZS1tYXA...

module: 错误能够还原到源文件。

hidden: 不会生成sourceMappingURL 这种映射。可以把source-map文件单独放在其他服务器,比如错误报警器。

tips: http响应头中可以使用source-map

组合类型:

eval: 没有源文件,只能定位行

eval-source-map: 可以映射源文件,并且可以定位行和列

cheap-source-map: 不可以映射源文件,但是只能定位行信息

eval-cheap-source-map: 转换es6以后的文件,不可以映射源文件,但是只能定位行信息

cheap-module-source-map: 可以映射源文件,只能显示行

hidden-source-map: 生成的打包文件中没有引入source-map文件,但是生成了source-map文件。适合第三方库。

nosource-source-map: 生成了map文件,但是看不到源代码,可以看到报错的文件和行列信息

source-map的选择:

    开发环境:cheap-module-eval-source-map

        隐藏了列信息,同时可以定位到源文件代码文件,同时生成单独的map文件,该文件放到eval中引进去。这种在内存中加载会相对比较快。

        生产环境: cheap-module-source-map

        只看到源文件的行信息。

注意: 不要不map文件放在公网,这样相当于暴露你的源码在外面了。