likes
comments
collection
share

什么是SourceMap?webpack devtool超详细解析

作者站长头像
站长
· 阅读数 49

你是否有过在控制台点击报错信息,却看到一堆混淆代码头晕眼花?你是否遇到即使定位到了报错代码,发现跟源码所在的行还不一样?

如果你也有上述苦恼,那就跟着本文花几分钟时间来了解与解决一下给你带来苦难的根源吧~

什么是SourceMap

在Web项目越来越庞大的今天,我们为了项目的性能和应对不同浏览器的兼容性,往往都会对需要上线的代码进行处理。比如对代码进行压缩混淆、ES6语法转ES5语法、多个文件合并与提取公共代码等。

这样一顿操作下来的结果就是我们代码的性能和兼容性虽然得到了提高,但也带来了调试上的困难。为了方便我们在线上环境或开发环境调试代码,SourceMap出现了。

SourceMap 是一个记录着源代码与转换后代码位置对应关系的文件,有了这个文件,我们就能通过点击控制台的报错信息直接跳转定位到对应源代码的报错位置(取决于相应配置)。

什么是SourceMap?webpack devtool超详细解析

使用 SourceMap

要想给打包后的代码引入 SourceMap,只需要配置 webpack 的 devtool 选项即可,devtool 就是控制是否生成,以及如何生成 SourceMap 的。

官方给出的 devtool 配置项多达25种,但无需害怕,我们只用了解其中2-3种就能满足我们的大部分使用场景。即使仍不能满足,但只要我们掌握 devtool 的组合方式,不管多麻烦的场景都不在话下。

下面让我们来具体了解一下吧!

不使用 SourceMap

作为一组对照试验,没有对比就没有伤害,让我们先来看看不使用 SourceMap 的情况下(devtool: false),我们点击控制台报错会看到什么。

什么是SourceMap?webpack devtool超详细解析

我们会看到控制台的报错变成了我们在配置文件中定义的 bundle.js,点击进去发现我们的代码和 webpack 的代码糅在了一块,因此报错代码的位置也发生了改变,更可怕的是,当我们开启了压缩混淆,我们想要读懂报错位置会变得更加困难!

这太糟糕了!SourceMap 没你真不行!

生成 SourceMap

我们给 devtool 配置一下

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist'),
  },
  devtool: 'cheap-source-map',
};

然后我们运行webpack,重新打开控制台查看报错

什么是SourceMap?webpack devtool超详细解析

很完美不是吗,但 cheap-source-map 代表什么意思呢?而且官方文档怎么会有25种那么多呢?

接下来让我们一步一步了解个中奥秘,以及如何组合他们。并且,在本文结尾,我们将列出几个日常开发中常用的且推荐的配置。

devtool 选项

devtoolperformanceproductionqualitycomment
(none)build: fastest rebuild: fastestyesbundleRecommended choice for production builds with maximum performance.
evalbuild: fast rebuild: fastestnogeneratedRecommended choice for development builds with maximum performance.
eval-cheap-source-mapbuild: ok rebuild: fastnotransformedTradeoff choice for development builds.
eval-cheap-module-source-mapbuild: slow rebuild: fastnooriginal linesTradeoff choice for development builds.
eval-source-mapbuild: slowest rebuild: oknooriginalRecommended choice for development builds with high quality SourceMaps.
cheap-source-mapbuild: ok rebuild: slownotransformed
cheap-module-source-mapbuild: slow rebuild: slownooriginal lines
source-mapbuild: slowest rebuild: slowestyesoriginalRecommended choice for production builds with high quality SourceMaps.
inline-cheap-source-mapbuild: ok rebuild: slownotransformed
inline-cheap-module-source-mapbuild: slow rebuild: slownooriginal lines
inline-source-mapbuild: slowest rebuild: slowestnooriginalPossible choice when publishing a single file
eval-nosources-cheap-source-mapbuild: ok rebuild: fastnotransformedsource code not included
eval-nosources-cheap-module-source-mapbuild: slow rebuild: fastnooriginal linessource code not included
eval-nosources-source-mapbuild: slowest rebuild: oknooriginalsource code not included
inline-nosources-cheap-source-mapbuild: ok rebuild: slownotransformedsource code not included
inline-nosources-cheap-module-source-mapbuild: slow rebuild: slownooriginal linessource code not included
inline-nosources-source-mapbuild: slowest rebuild: slowestnooriginalsource code not included
nosources-cheap-source-mapbuild: ok rebuild: slownotransformedsource code not included
nosources-cheap-module-source-mapbuild: slow rebuild: slownooriginal linessource code not included
nosources-source-mapbuild: slowest rebuild: slowestyesoriginalsource code not included
hidden-nosources-cheap-source-mapbuild: ok rebuild: slownotransformedno reference, source code not included
hidden-nosources-cheap-module-source-mapbuild: slow rebuild: slownooriginal linesno reference, source code not included
hidden-nosources-source-mapbuild: slowest rebuild: slowestyesoriginalno reference, source code not included
hidden-cheap-source-mapbuild: ok rebuild: slownotransformedno reference
hidden-cheap-module-source-mapbuild: slow rebuild: slownooriginal linesno reference
hidden-source-mapbuild: slowest rebuild: slowestyesoriginalno reference. Possible choice when using SourceMap only for error reporting purposes.

组合方式

通过阅读 devtool 的配置项,我们可以提取出一些相通的东西。

evalinlinehiddennosourcescheap

这几个其实就是一种组合关系,他们的组合方程式如下

[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

其中:

  • inline-|hidden-|eval:三个值时三选一;
  • cheap可选值,并且可以跟随module的值;
  • nosources:可选值。

具体都有什么作用,我们接着往下看。

inline

inline 会将 SourceMap 内联到原始文件中,不会生成额外的 【source map】 文件。

什么意思呢?比如我使用cheap-source-map进行打包。可以看到 dist 目录下有这么一个文件

什么是SourceMap?webpack devtool超详细解析

这个 .map 文件对应着每一个打包后的 js 文件,用来与相对应的文件进行代码定位与匹配。

每一个.map 文件都有一套格式,比如这个bundle.js.map文件就写着一套标准【SourceMap】格式。

什么是SourceMap?webpack devtool超详细解析

它包含的意思如下:

  • file: 该 SourceMap 对应的文件的名称
  • mappings: 压缩混淆后的代码定位源代码的位置信息
  • names: 源文件中的变量名
  • sourceRoot: 源文件根目录,这个值会加在每个源文件之前
  • sourcesContent: 源代码字符串列表,用于调试时展示源文件,列表每一项对应于sources
  • sources: 源文件列表
  • version: SourceMap的版本

而相应的被 【SourceMap】 对应的文件下,结尾也会标上相应的信息# sourceMappingURL=xxx.js.map,比如这个例子中的bundle.js标记如下:

什么是SourceMap?webpack devtool超详细解析

浏览器在加载bundle.js时,会通过这个标记找到对应的 .map 文件,然后加载其中的 sources 字段,在控制台中生成对应的目录结构,再把 sourcesContent 中的内容按顺序写入相应的生成的目录文件中。而如果我们使用inline,那么标记后的bundle.js.map则会直接被 【base64】 编码,然后拼接到后面去。

什么是SourceMap?webpack devtool超详细解析

eval

使用 eval 生成 SourceMap,也不会生成额外的 .map 文件,因为 eval 中为字符串形式,所以当源码变动的时候进行字符串处理会提升 rebuild 的速度。

虽然重新编译的速度很快,但 eval 也是有缺点的,比如容易遭到 XSS 攻击,且在旧的浏览器下性能会很不理想。

在现代浏览器中有两种编译模式:fast path 和 slow path。fast path 是编译那些稳定和可预测(stable and predictable)的代码。而明显的,eval 不可预测,所以将会使用 slow path。在旧的浏览器中,使用 eval 的性能会大幅下降。

所以,eval 一般只用于开发环境,不会用于打包线上环境的代码。

hidden

hidden 会生成 .map 文件,但不会在编译后的代码内添加上面提到的那个标记,因此点击报错信息在控制台中是看不到源码的,在开发场景下,使用调试控制台查看报错的信息,效果等同于devtool: false

但这种可以用于错误收集等场景,出错时前端把出错的行列传给服务端,服务端根据行列以及.map文件解析出出错的源码位置。

cheap

cheap可以单用,也可以拼接 module(即cheap-module)使用。

cheap 会忽略列信息,【SourceMap】只有行映射,可以加快打包速度。需要注意的是,moudle 一定是跟 cheap 一起使用的, 表示所映射的阶段, 如果没有 module 映射的是 loader 处理后的代码信息,如果加了 module 那就是 loader 处理前的源码。

nosources

使用nosources可以使得【sourceMap】中不带源码,即没有sourcesContent的内容,但仍会有准确的错误行列信息,可以避免源码泄露。

常用配置推荐

开发环境推荐使用

  • eval-cheap-source-map
  • eval-cheap-module-source-map

生产环境推荐使用

  • hidden-source-map
  • nosources-source-map

总结

SourceMap 是一个记录着源代码与转换后代码位置对应关系的文件,有了这个文件,当代码出现异常报错的时候,我们就可以准确定位到具体的位置,同时在某些配置下,我们还能在浏览器控制台直接查看报错的源代码。

在 webpack 中使用 SourceMap 的关键是使用 devtool,而想要用好 devtool 就要弄明白evalinlinehiddennosourcescheap 这些关键字的含义,剩下的不过是如同拼积木一般的【组装】罢了。

转载自:https://juejin.cn/post/7245536612628971581
评论
请登录