一直以来对source map 都懵懵懂懂, 被webpack 所提供的多样的source 给乱花了眼。 这次就决定来一一尝试一下各种source map的区别
什么是source map
现代的前端开发总是伴随的各种框架, 在使用这些框架开发的代码需要经过编译才可以在生产环节使用, 编译后就伴随着可读性的降低,也会影响我们的错误调试。
那source map就是为了解决这个问题。
Source map可以理解为一个地图, 通过它可以获知编译后的代码 对应编译前的代码位置。这样当代码遇到异常, 我们就可以通过报错信息定位至准确的位置。 同时在浏览器 sources 也可以查看到源码。
编译后的代码内只需要包含这样一句
// @ sourceMappingURL=map文件路径
就可以关联上 source map文件了
devtool
webpack 通过 devtool
控制需要生成的 source map 类型
我们来看一下 devtool
的支持的属性devtool, 可以看到 source map 同时也分为很多种,但大体上都是加载形式的区别, 本质的核心还是相同的。
把它们罗列出来居然有这么多
- eval
- eval-cheap-source-map
- eval-cheap-module-source-map
- eval-source-map
- cheap-source-map
- cheap-module-source-map
- source-map
- inline-cheap-source-map
- inline-cheap-module-source-map
- inline-source-map
- eval-nosources-cheap-source-map
- eval-nosources-cheap-module-source-map
- eval-nosources-source-map
- inline-nosources-cheap-source-map
- inline-nosources-cheap-module-source-map
- inline-nosources-source-map
- nosources-cheap-source-map
- nosources-cheap-module-source-map
- nosources-source-map
- hidden-nosources-cheap-source-map
- hidden-nosources-cheap-module-source-map
- hidden-nosources-source-map
- hidden-cheap-source-map
- hidden-cheap-module-source-map
- hidden-source-map
看到这么多,已经开始慌了。 不过不用怕, 其实我们理解核心的几个关键字就可以了。
来看一下文档上对这些命名的解释,
- eval-* :使用eval 生成source map , 不会生成额外的 .map 文件, 而是在eval 函数内附加 source map 。 推荐用于开发环境, 因为* 相对来说构建和热更新都比较快。
- inline-* : 将SourceMap内联到原始文件中,同样 不会生成额外的 .map 文件。
- hidden-* :addition会生成source map 但是不会将其关联, 也就是不会在编译后的代码内添加上面提到的那个映射语句。
- nosources-* :sourcemap 中不带源码, 但会有准确的错误行列信息, 避免源码泄露。
- cheap-* : 忽略列信息,source map 只有行映射,可以加快打包速度
- cheap-module-* : moudle 关键子一定是跟 cheap 一起使用的, 表示所映射的阶段, 如果没有 module 映射的是 loader 处理前的代码信息,如果加了 module 那就是 loader 处理后的源码, 举个例子,
const a = 1
这行, 如果没加 module 那拿到的就是转为 es5 的var a = 1
, 如果加了module , 那拿到的就是const a = 1
理解了这些之后,再来看上面这一堆不同类型的 source map 也就能看懂了。
什么? 还不懂? 那我们来动手尝试一下几个典型的!
我们在代码内故意打印未定义的变量 c
, 看看不同的 source map 下的错误信息结果
注意: 行号为 9
eval
修改配置
首先我们在 devtool 填写 eval 。
运行构建
进行一次 run build 构建看看。
可以看到生成的结果, 上方注释写明了这是来自哪个文件的编译结果, 当然这个是 webpack 的加载逻辑, 我们这里可以不用太过关系, 往内部看, 内部是一个 eval 函数, 内部是编译后的代码。
然后我们看到末尾, eval 的末尾有 sourceURL=webpack:///./src/views/About.vue?
。
错误信息
然后我们运行一下项目, 看看他的报错信息如何。
可以看到其实并不是非常清晰的, 瞅一眼大概能明白是哪个文件爆的错, 但行号之类的完全不对,而且点击进去的也是编译后的信息
查看详情:
完全是编译后的代码。
这就是 eval 模式下的 source map 方式, 他不会生成实际的 .map 文件, 但会在 eval 函数末尾添加对原本文件的映射语句, 指向源文件本地地址, 同时调试体验也较差。 因此也就无法在生产环境使用了。
如果想要更清晰的错误信息还是需要使用 eval-source-map
source-map
最标准的 source-map 打包形式
修改配置:
运行构建:
可以看到生成了很多 .map 文件
进入一份js文件, 我们可以看到代码的末尾关联了一份 .map 文件
错误信息:
可以看到错误定位还是比较准确的, 找到了正确的 9 行,然后我们点进去看看
很完美,是我们正确的源码信息, 并且成功定位到具体列。
inline-source-map
运行构建:
没有 .map 文件的产出
source map 数据直接内联
错误信息:
能定位到 行号
查看详情:
完美展示,同样也能够定位至列
nosources-source-map
运行构建:
有 .map 文件
有路径映射
错误信息:
行号准确
查看详情:
没有源码信息, 无法加载
hidden-source-map
运行构建:
有 .map 文件
没有映射路径
错误信息:
错误信息模糊
查看详情:
完全是编译后的代码
cheap-source-map
运行构建:
有 .map 文件
有映射路径
错误信息:
行号不正确
查看详情:
是被处理过的代码,并且没有定位到具体列
cheap-module-source-map
运行构建:
有 .map 文件
有映射路径
错误信息:
行号正确
查看详情:
正确的源码,但无法定位到具体列。
结尾
搞清楚 source map 这些区别的关键就在于先要弄懂关键字所表示的含义,其余的都是 “组装” 。
本文由博客一文多发平台 OpenWrite 发布!