我在开发一个json转化成ts类型的功能时,用到了一个json2ts的库。本着看源码学原理的精神,我打开了源码,第一眼就看到了一个.map为后缀的文件。

作为一个前端小白,我并不知道.map文件是啥,所以我就开始了我的谷歌搜索之旅,也就是我们本文的主题——Source map。

首先,不急着讲Source map是什么,我们先了解一下背景。

如今,大部分源码都需要经过转换才能投入生产环境,如早期的jquery,现在流行的框架vue、react等。

而源码转换后,都使得实际运行的代码不同于开发代码,在debug时就变得几乎无法看懂。转换后的代码在报错定位时,一行可能有成千上万个字符,变量名可能被修改,你完全无法看出代码出了什么问题。那咋整呢?

这就是Source map要解决的问题。

Source map,用官方点的话来说,是保存源代码映射关系的文件。简单来说,他就是一个信息文件,他是一个独立的map文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。

有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。

康康例子,对比一下使用前和使用后(借用了阮一峰老师的图片):

如何启用Source map

只要在转换后的代码尾部,加上一行就可以了。以json2ts源码为例:

//# sourceMappingURL=json2ts.js.map

然后在chrome浏览器的开发者工具 -> 设置中,把Enable JavaScript source maps钩上就完事了。

如何生成Source map

  • Google的Closure编译器
  • 我进入他的官网,用Google翻译给他翻译了一下(英文水平属实有限),让我们来看看他的定义:

    看到这,我感觉这玩意有点牛的啊,有种eslint加强版的感觉,不仅能检查语法,还能优化你的代码。

    到这我又有了新的疑问:

    这么厉害的东西,项目应该很常用吧?是不是可以用webpack插件引入呢?

    这个问题我文章后头会提到,现在我们先继续看看这个Source map。

    Source map的格式

    我们再看看Source map文件里头的样子(举个简单例子):

        version : 3,     file: "out.js",     sourceRoot : "",     sources: ["foo.js", "bar.js"],     names: ["src", "maps", "are", "fun"],     mappings: "AAgBC,SAAQ,CAAEA"

    这个文件是一个js对象,可以被解释器读取。我们来看看他各个属性的意思:

    version:Source map的版本,此处为3。

    file:转换后的文件名。

    sourceRoot:转换前的文件所在的目录。如果与转换前的文件在同一目录,该项为空。

    sources:转换前的文件。该项是一个数组,表示可能存在多个文件合并。

    names:转换前的所有变量名和属性名。

    mappings:记录位置信息的字符串。

    在这我们简单讲一讲mapping属性,他的作用是让两个文件的各个位置一一对应。

    用分号(;)表示行对应,每个分号对应转换后源码的一行。

    用逗号(,)表示位置对应,每个逗号对应转换后源码的一个位置。

    用VLQ编码表示位置转换,代表该位置对应的转换前的源码位置。

    举个例子:

    mappings:"AAAAA,BBBBB;CCCCC"
    

    表示:转换后的源码分成两行,第一行有两个位置,第二行有一个位置。

    关于位置对应的原理和VLQ源码,我在这就不详细说明了,感兴趣的同学可以去看看阮一峰老师的JavaScript Source Map 详解

    接下来,让我们回过头来看看前面提到的两个疑问:

    webpack是否有关于source map的配置?

    关于优化代码,他是怎么实现的呢?

    webpack的source map

    webpack是有关于source map的设置的,也就是配置devtool。

    最简单的配置,就是:

      devtool: 'source-map'
    

    当然你也可以使用 SourceMapDevToolPlugin 进行更细粒度的配置。查看 source-map-loader 来处理已有的 source map。

    常见配置信息如下:

    eval: 生成代码 每个模块都被eval执行,并且存在@sourceURL

    cheap-eval-source-map: 转换代码(行内) 每个模块被eval执行,并且sourcemap作为eval的一个dataurl

    cheap-module-eval-source-map: 原始代码(只有行内) 同样道理,但是更高的质量和更低的性能

    eval-source-map: 原始代码 同样道理,但是最高的质量和最低的性能

    cheap-source-map: 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用

    cheap-module-source-map: 原始代码(只有行内) 与上面一样除了每行特点的从loader中进行映射

    source-map: 原始代码 最好的sourcemap质量有完整的结果,但是会很慢。

    JavaScript Source Map 详解

    什么是Closure编译器?

    打破砂锅问到底:详解Webpack中的sourcemap

    webpack Devtool

    分类:
    前端
  •