经过 Webpack 打包后的代码运行在浏览器上时,和开发者编写的代码是有差异的:例如 ES6 的代码可能被转换成 ES5 的代码;代码对应的行号、列号在经过编译后不一致;代码进行压缩丑化后会修改编码名称;TypeScript 编写的代码被转换成 JavaScript 等。当代码报错需要调试时,调试这种转换后不一致的代码是很困难的。
要调试这种转换后不一致的代码,可以使用 source-map
。 source-map
是一种可以将已转换的代码映射到源文件的文件,使浏览器可以重构源代码文件并在调试器中显示重构的源代码文件,方便开发者调试。
使用 source-map
:
-
在
webpack.config.js
配置文件中配置devtool: 'source-map'
,运行webpack
命令后将会根据源文件生成source-map
文件。module.exports = { devtool: 'source-map', }
-
在 Webpack 打包生成的文件最后添加一个注释,指向
source-map
文件(Webpack 会自动添加)。注释的格式是固定的,浏览器会读取注释,根据注释指向的 URL 自动下载
source-map
文件;然后根据打包生成的文件和source-map
文件还原出源代码文件。
如果代码报错需要调试,点击报错的信息浏览器就会自动映射到源文件中对应报错的行和列。 -
在浏览器中运行代码。
配置 source-map
:
devtool:配置是否生成以及如何生成 source-map
。devtool 有很多属性值,选择不同的属性值,生成的 source-map
不同,打包的过程也会有性能的差异。可以根据不同的情况进行选择。
mode:development
模式下,devtool 的默认值是 eval。
mode: production
模式下,默认不配置 devtool 选项。
属性值:
devtool 有很多属性值,其实就是 eval、cheap、inline、hidden、nosources、source-map
的各种组合。
常用的属性值有:
-
false:布尔值。完全不使用
source-map
,不生成任何和source-map
相关的任何内容。
浏览器的报错信息只会显示出打包后生成的文件。 -
eval:字符串。不生成
source-map
文件,但是在打包生成的文件中会使用 eval 函数,并且在 eval 函数的代码最后添加注释//#sourceURL=
指向源文件;它在浏览器执行时会被解析,在调试面板中会生成对应的文件目录。除了完全不使用source-map
外,eval 打包的速度是最快的。
浏览器的报错信息会指出具体报错的文件,并且点击能跳转到对应文件。
-
suorce-map
:字符串。会生成一个独立的完整的source-map
文件,在打包生成的文件最后会有一个注释指向该source-map
文件,在浏览器中解析执行时会被还原出所有的源代码文件。
浏览器的报错信息会指出具体报错的文件,并且点击能跳转到对应文件。 -
eval-source-map
:字符串。不生成source-map
文件,但是在打包生成的文件中会使用 eval 函数,并且将source-map
的具体内容以 DataURL 的形式添加到 eval 函数的最后面。浏览器在请求打包生成的文件时就会一同将source-map
的内容请求下来并解析执行。
-
inline-source-map
:字符串。不生成source-map
文件,但是source-map
的具体内容会以 DataURL 的形式添加到打包生成的文件最后。浏览器在请求打包生成的文件时就会一同将source-map
的内容请求下来并解析执行。
-
cheap-source-map
:字符串。和设置source-map
属性值的表现类似,会生成独立的source-map
文件,但是只有行映射,没有列映射。因此比source-map
效率会高一些。也就是说,在浏览器器中定位错误的时候只能定位到行,无法定位到列。
-
cheap-module-source-map
:字符串。和设置cheap-source-map
属性值的表现类似,但是,如果代码中使用 loader 转换代码,使用cheap-source-map
后浏览器还原的源文件和真实的源文件还有差异(例如:行、列等的会对应不上),使用cheap-module-source-map
则一致。 -
hidden-source-map
:字符串。和设置source-map
属性值的表现类似,会生成一个独立的完整的source-map
文件,但是在打包生成的文件最后指向source-map
文件的注释会被删除,也就是不会对source-map
文件进行引用 ,在浏览器中也就无法准确地定位错误。 -
nosources-source-map
:字符串。会生成source-map
文件,但是生成的source-map
只有错误信息的提示,不会生成源代码文件。
浏览器的报错信息会指出具体报错的文件,但是点击无法跳转到对应文件。
带有 source-map
的属性值的组合规则:
[inline- | hidden- | eval-] [nosources-] [cheap-[module-]] source-map
- inline/hidden/eval:如果有的话在最开头,三选一。
- inline:生成的
source-map
的内容以 DataURL 的形式跟在打包生成的文件最后。 - hidden:生成
source-map
文件,但是不会对source-map
文件进行引用。 - eval:在打包生成的文件中使用 eval 函数并且会添加注释指向
source-map
。
- inline:生成的
- nosources:生成
source-map
文件,但是在浏览器中看不到源代码。如果有的话在第二位。 - cheap:生成
source-map
文件,但是在浏览器中只有行提示、没有列提示。如果有的话在第三位。后面还可以跟 module。
Chrome 浏览器对 source-map
的支持:
在 Chrome 浏览器中有开关可以开启或关闭对 source-map
的支持。
source-map
文件分析:
source-map
第一版生成的文件大约是原文件的 10 倍,第二版减少了 50%,第三版又减少了 50%,所以目前一个 133kb 的文件生成的source-map
文件大概在 300kb 左右。
source-map
文件是一个对象。其中的属性有:
- version:当前
source-map
的版本。 - file:打包生成的文件。
- names:转换之前的变量名和属性名。
- sources:源文件。
- sourcesContent:源代码。
- sourceRoute:sources 中源文件相对的根目录。
- mappings:
source-map
用来和源文件进行映射的信息(例如位置信息等)。经过 base64 VLQ 编码。
开发中的最佳实践:
- 开发阶段:推荐使用
source-map
或者cheap-module-source-map
,可以准确地获取报错信息,方便开发调试。Vue 使用的是
source-map
;React 使用的是cheap-module-source-map
。 - 测试阶段:也推荐使用
source-map
或者cheap-module-source-map
。 - 发布阶段:推荐使用 false,或者缺省 devtool 选项。