source-map作用
我们的代码通常运行在浏览器上时,是通过打包压缩的,也就是真实跑在浏览器上的代码,和我们编写的代码其实是有差异的。 比如:
- ES6的代码可能被转换成ES5
- 对应的代码行号、列号在经过编译后肯定会不一致
- 代码进行丑化压缩时,会将编码名称等修改
- 使用了TypeScript等方式编写的代码,最终转换成JavaScript
当代码报错需要调试时(debug),调试转换后的代码是很困难的,source-map 可以调试这种转换后不一致的代码,source-map是从已转换的代码,映射到原始的源文件,使浏览器可以重构原始源并在调试器中显示重建的原始源。
source-map过程
source-map使用
- 根据源文件,生成source-map文件,webpack在打包时,可以通过配置生成 source-map
- 在转换后的代码,最后添加一个注释,它指向sourcemap
//# sourceMappingURL=common.bundle.js.map,浏览器会根据我们的注释,查找相应的source-map,并且根据 source-map 还原我们的代码,方便进行调试。 webpack 有了 source-map 的配置之后,打包会自动生成 source-map 文件。
module.exports = {
devtool: "source-map"
}
打包之后
执行打包后的文件最后一行会有注释指向该打包文件的 source-map 文件。浏览器根据这个注释,自动下载 source-map 文件。
打包后的文件和 source-map 文件都有了之后,浏览器会还原源代码,可以排查代码错误。
如果打包后的代码有报错,可以直接在报错信息看到原代码文件。
chrome 支持 source-map
打开控制台,点击齿轮图标。
source-map 文件内容解读
{
// version:当前使用的初source-map版本,也就是最新的第三版
"version": 3,
// sources:从哪些文件转换过来的source-map和打包的代码(最初始的文件)
"sources": [
"webpack:./src/index.js",
"webpack:./src/js/format.js",
"webpack:./src/js/math.js",
"webpack:/webpack/bootstrap",
"webpack:k/webpack/runtime/compat get default export",
"webpack:/webpack/runtime/define property getters",
"webpack:/webpack/runtime/hasOwnProperty shorthand",
"webpack:/webpack/runtime/make namespace object",
"webpack:/webpack/startup"
],
// names:转换前的变量和属性名称
"names": [
"require",
"sum",
"mul",
"console",
"log",
"dateFormat",
"priceFormat",
"abc",
"date",
"price",
"module",
"exports",
"num1",
"num2"
],
// source-map用来和源文件映射的信息(比如位置信息等)base64编码
"mappings": ";;;;;;;;;;;;;AAAA;eACqBA,mBAAO,CAAC,mCAAD,C;IAApBC,G,YAAAA,G;IAAKC,G,YAAAA,G,EAEb;;;AACA;AAEAC,OAAO,CAACC,GAAR,CAAYH,GAAG,CAAC,EAAD,EAAK,EAAL,CAAf;AACAE,OAAO,CAACC,GAAR,CAAYF,GAAG,CAAC,EAAD,EAAK,EAAL,CAAf;AAEAC,OAAO,CAACC,GAAR,CAAYC,sDAAU,CAAC,KAAD,CAAtB;AACAF,OAAO,CAACC,GAAR,CAAYE,uDAAW,CAAC,KAAD,CAAvB;AAEAH,OAAO,CAACC,GAAR,CAAYG,GAAZ,E;;;;;;;;;;ACZA,IAAMF,UAAU,GAAG,SAAbA,UAAa,CAACG,IAAD,EAAU;AAC3B,SAAO,YAAP;AACD,CAFD;;AAIA,IAAMF,WAAW,GAAG,SAAdA,WAAc,CAACG,KAAD,EAAW;AAC7B,SAAO,QAAP;AACD,CAFD,C,CAIA;;;AAEAC,MAAM,CAACC,OAAP,GAAiB;AACfN,YAAU,EAAVA,UADe;AAEfC,aAAW,EAAXA;AAFe,CAAjB,C;;;;;;;;;;;;;;;;ACVO,IAAML,GAAG,GAAG,SAANA,GAAM,CAACW,IAAD,EAAOC,IAAP,EAAgB;AACjC,SAAOD,IAAI,GAAGC,IAAd;AACD,CAFM;AAIA,IAAMX,GAAG,GAAG,SAANA,GAAM,CAACU,IAAD,EAAOC,IAAP,EAAgB;AACjC,SAAOD,IAAI,GAAGC,IAAd;AACD,CAFM,C;;;;;;UCJP;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCrBA;WACA;WACA;WACA,cAAc,0BAA0B,EAAE;WAC1C,cAAc,eAAe;WAC7B,gCAAgC,YAAY;WAC5C;WACA,E;;;;;WCPA;WACA;WACA;WACA;WACA,wCAAwC,yCAAyC;WACjF;WACA;WACA,E;;;;;WCPA,6CAA6C,wDAAwD,E;;;;;WCArG;WACA;WACA;WACA,sDAAsD,kBAAkB;WACxE;WACA,+CAA+C,cAAc;WAC7D,E;;;;UCNA;UACA;UACA;UACA",
// 打包后的文件(浏览器加载的文件)
"file": "js/bundle.js",
// 所有的sources相对的根目录
"sourceRoot": ""
}
source-map 可配置项
webpack 提供了非常多的选项(目前是26个),来处理 source-map,选择不同的值,生成的 source-map 会稍微有差异,打包的过程也会有性能的差异,可以根据不同的情况进行选择。 Devtool | webpack 中文文档 (docschina.org)
1. 下面几个值不会生成 source-map 文件
- false:不使用source-map,也就是没有任何和source-map相关的内容。
- none:production 模式下的默认值,不生成source-map。
以上两种方式没办法还原源代码。 - eval:development 模式下的默认值,不生成source-map,但是它会在打包后的代码中 eval 执行的代码中,添加
//# sourceURL=;被浏览器在执行时解析,并且在调试面板中生成对应的一些文件目录,方便我们调试代码。eval函数将原来的代码加上字符串,使用 eval 的目的是 eval 函数后面可以加//# sourceURL=;eval 虽然没有生成 map 文件,但是可以还原源代码,打包速度快。
2. 生成 source-map 文件的配置
- source-map
生成了独立的 source-map 文件,在 bundle 文件中有注释,指向 source-map 文件。 - eval-source-map
会生成 sourcemap,但是 source-map 是以 base64 的方式添加到 eval 函数的后面。source-map文件和 build.js 文件放在一起了。 - inline-source-map
作用:生成 sourcemap,但是 source-map 是以 base64 添加到 bundle 文件的后面。 - cheap-source-map
作用:生成 sourcemap,但是会更加高效一些(cheap低开销),因为它没有生成列映射(Column Mapping) - cheap-module-source-map
生成 sourcemap,类似于cheap-source-map,但是对源自loader的sourcemap处理会更好(例如 ts-loader将 ts 文件转换为 js 文件,babel会把箭头函数等转换为js)
cheap-source-map和cheap-module-source-map的区别?
源代码:
const dataFormat = () => {
return "2020-12-12"
}
const priceFormat = () => {
return "100.00"
}
module.export = {
dataFormat,
priceFormat
}
babel 配置后
打包后的代码:
上面的截图就能看出 "cheap-source-map"对loader处理的代码上面加了多余的代码。"cheap-module-source-map"处理后的代码和源代码完全相同。
- hidden-source-map 生成 sourcemap,但是不会对 source-map 文件进行引用,相当于删除了打包文件中对sourcemap的引用注释
// 被删除掉的
//# sourceMappingURL=bundle.js.map
手动添加进来,那么 sourcemap 就会生效了。
- nosources-source-map
生成sourcemap,但是生成的sourcemap只有错误信息的提示,不会生成源代码文件;点击错误提示,无法查看源码:
sourceMap 多个值的组合
webpack 提供给我们的26个值,是可以进行多组合的。
组合的规则如下:
- inline-|hidden-|eval:三个值时三选一
- nosources:可选值
- cheap可选值,并且可以跟随module的值
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
source-map 最佳实践
- 开发阶段:推荐使用 source-map 或者 cheap-module-source-map ,这分别是vue和react使用的值,可以获取调试信息,方便快速开发。
- 测试阶段:推荐使用 source-map或者cheap-module-source-map 测试阶段我们也希望在浏览器下看到正确的错误提示。
- 发布阶段:false、缺省值(不写)