学习一个东西要知道它为什么会出现,我觉得这是很重要的,所以先简单提一嘴。webpack作为现在前端工程化最热门的打包工具之一,能够帮助我们快速地打包和编译浏览器不认识的 web 资源,在webpack的默认配置下打包过的代码是经过压缩丑化的,在代码量较少时还可以进行调试,但当代码量增加时调试难度就会level up up up up,devtool配置就是帮我们解决这个问题的。通过在devtool中配置相关的source-map风格就可以大大降低我们的调试难度。注意,本文有三个关键名词即sourcemap风格、sourcemap、devtool。
首先简单解释一下三者的关系,sourcemap文件是sourcemap风格的一种,然后devtool可以选择应用哪种sourcemap风格
对于devtool官方解释为
此项用于控制如何生成
source map(也就是生成何种风格的source map)
对于source mapMDN解释为
source map 是从已转换的代码映射到原始源的文件,使浏览器能够重构原始源并在调试器中显示重建的原始源。
下面将source map拆分来讲解,即:如何生成source map,浏览器是怎么通过source map来对应到源代码的,一些常见的source map配置
如何生成source map
比较简单不做赘述,在webpack配置文件中进行如下配置
module.exports = {
//其它省略
devtool: "source-map"//这是风格最普通的sourcemap还可以设置为cheap-source-map等等
}
即可在打包出的文件中找到map文件。这里如果map文件为一行不便于阅读的话可以选中并按shift+alt+f对代码进行一个美化。在阅读的同时可以将mode配置更改为development模式来观察打包后的代码以及map文件。
浏览器如何通过sourcemap来对应到源代码的
在devtool配置为source-map这个风格时会生成map文件并且打包生成的bundle.js的最后一行会有这样一段代码
//# sourceMappingURL=bundle.js.map
浏览器便是靠这段代码找到对应的map文件,对于一段console.log("1"),map文件的内容为:
{
"version": 3,
"file": "bundle.js",
"mappings": "AAAAA,QAAQC,IAAI",
"sources": ["webpack://webpack-note/./src/index.js"],
"sourcesContent": ["console.log(\"1\")"],
"names": ["console", "log"],
"sourceRoot": ""
}
version: 即为sorce-map版本,1.0版本生成的map文件为源文件的10倍大小,到3.0版本优化到了2.5倍大小。file: 打包后的代码(与源文件关联的生成文件名)mappings: 包含实际映射的 base64 VLQ 字符串,里面的信息一般有位置信息等、比如例子中console在源文件的第几行第几列,第几个源文件,在压缩文件的第几行,对应names数组中的哪个值这五个信息。(这里我觉得可以不用深究,反正只要知道五个字母分别代表了不同的信息即可)sources: 原始源文件的url数组sourcesContent: 原始源文件的实际内容names: 转换前的变量和属性名称sourceRoot: 所有源文件对应的根目录 浏览器通过这样一个map文件并且结合AST(抽象语法树)就可以知道打包后的各个代码在源代码的哪一个位置了。 github.com/mozilla/sou… 也可以自己去看source-map的官方解释,如果发现有讲的不对的地方希望回来指正。
下面说一说常用的sourcemap风格以及各种风格的特性
cheap-source-map与cheap-module-source-map
cheap-source-map风格即生成低开销的sourcemap,它不会生成列映射所以生成速度更快,在实际开发中,一般我们只用知道是哪一行错误了就可以定位到错误,所以这个sourcemap风格是一个不错的选择。
{
"version": 3,
"file": "bundle.js",
"mappings": ";;;;;AAAA",
"sources": ["webpack://webpack-note/./src/index.js"],
"sourcesContent": ["console.log(\"1\");"],
"names": [],
"sourceRoot": ""
}
这个低开销在map文件中的mapings可以体现,普通sourcemap中mapings的每一个字符串有5位而低开销中只有4位就是缺少了源代码的列信息。
cheap-module-source-map与cheap-source-map的区别就在于前者对于对源自loader的sourcemap处理会更好。举个例子就是后者如果处理babel编译后的代码,那么行号等信息可以无法正确对应上,也就是说虽然报错时具体哪一句是会报出但行号会有一些偏差,而后者就可以避免这些错误。
eval、eval-source-map和inline-source-map
这前两种sourcemap风格虽然名字相似,但生成的内容有比较大的不同。
eval风格不会生成sourcemap文件可以视为一钟特殊的source-map,最后浏览器是通过打包后的代码中的eval函数后的baseURL来找到对应的源文件,这种方式是生成速度最快的sourcemap风格。但是不生成sourcemap文件意味着无法准确的对应行号,所以报错信息方面没有这么准确。
一个例子:
eval("console.log(\"1\");\n\n//# sourceURL=webpack://webpack-note/./src/index.js?");
eval-source-map与inline-source-map这两个风格都可以生成sourcemap但是都没有单独放在map文件中,前者的sourcemap文件内容放在eval的后面,后者的sourcemap文件内容放在打包代码的最后。
vue和react框架脚手架默认的sourcemap风格
vue-cli在开发环境中为source-map而在生产环境中为false或者source-map(具体要在config的index.js之中调整对应的参数)
react脚手架在开发环境中默认的是cheap-module-source-map在生产环境默认的似乎是缺省值或者false大家可以自行去查阅。
最后
很久没写文章了,一直在思考我自己存在的问题,过段时间会考虑混一混年终总结😄