线上调试代码,试试 SourceMap?
背景
大家有没有过在开发环境代理调试的时候,只能调试打包之后的代码,而不是调试源码?
那是因为没正确使用 sourceMap。
SourceMap
sourceMap 有什么作用?🤔
sourceMap 用于映射编译后的代码与源码,这样如果编译后的代码出错了,可以很快速的定位到源文件的位置。
举个栗子 🌰
umi 的项目在开发环境默认的 sourceMap 为 cheap-module-source-map。
我们把它关了,看看编译的资源有什么不一样的:
// config.ts
devtool: false,
既然 sourceMap 可以快速定位到源码的位置,为了方便,我们在页面上执行个 console.log,看看 log 位置的源代码:
console.log('测试 SourceMap')
打印出来发现我们
log 处的源码是编译之后的。
目前不加 SourceMap 的结论 😳
不加
sourceMap,页面上的log信息是无法精准定位到源码的位置的。
那我们加了呢?
先试试 bigfish 默认的,我们把 config 里的 devtool 删掉。
结果发现还是定位不到源码位置,控制台提示:source map failed to load。
而且文件最后一行已经显示了 sourceMappingURL 的指定文件。
那是为什么?map 文件加载失败了。
仔细看发现它请求的位置是线上环境的 map 文件,请求了 404。
而 umi 在生产环境不会打开 sourceMap(为了防止其他人可以随意在 source 上看到自己的源码)。
奇怪的是我们在 Network 里并没发现请求的 map 文件。
查阅资料发现:
SourceMap 的加载不能从 Network 中看到,而要从 Developer Resources 看到。
打开 Developer Resources:command + shift + p 搜索 Show Developer Resources。
在 Developer Resources 中可以看到 map 文件请求失败:
ERROR LOADING URL http://xxx.alipay.net/static-assets/.../P_ALARMLABELMANAGEMENT_INDEX.ASYNC.JS.MAP:
HTTP ERROR: STATUS CODE 404, NET::ERR_HTTP_RESPONSE_CODE_FAILURE
用 XSwitch 转发 map 文件行不行?
那我们把这个地址通过 xswitch 代理转发到本地是不是就可以了?
试了下,遗憾的说:不行。
参考资料:zhuanlan.zhihu.com/p/674981525
原因分析:
- 只有在 DevTools 打开时才会加载 SourceMap(性能优化 & 用户并不需要)
- DevTools 也是一种扩展,而扩展是无法拦截另一个扩展的请求的(安全性问题)
- SourceMap 的加载不能从 Network 中看到而要从 Developer Resources 看到(这也是故意的设计)
基于以上信息,Chrome Extension 主要还是用于折腾 Content 区域,而不是希望你 Hack 浏览器。总之很遗憾,我们不能通过 XSwitch 这样的插件,把 SourceMap 文件的请求地址转发到正确的位置。
解决方案:使用不生成新 map 文件的 SourceMap 类型
目前看我们只能使用不生成新 map 文件的 sourceMap 类型了。
因为 sourceMap 的类型有很多,以下是不会生成新 map 文件的类型对比:
| 类型 | 构建速度 | 调试精度 | 推荐环境 |
|---|---|---|---|
eval | 最快 | 低 | 快速开发 |
eval-cheap-source-map | 快 | 行级别 | 开发环境 |
eval-cheap-module-source-map | 较快 | 行级别(含 Loader) | 开发环境(推荐) |
eval-source-map | 慢 | 精确 | 精确调试 |
inline-source-map | 慢 | 精确 | 特殊需求 |
false | 最快 | 无 | 生产环境 |
AI 推荐我们开发环境用 eval-cheap-module-source-map。
配置如下:
devtool: 'eval-cheap-module-source-map',
验证结果:
✅ 使用 eval-cheap-module-source-map 确实可以定位到源码了!
控制台的 log 信息直接指向了源文件:useProtableProps.tsx:76,而不是编译后的代码。
加了 SourceMap 的结论 🤓
在线上代理的方法上使用默认的 bigfish 的 devtool 值做不到定位源码,我们使用了 eval-cheap-module-source-map,可以在开发环境定位到源码位置,方便调试。
总结 👀
建议大家设置 devtool:
- 开发环境:
eval-cheap-module-source-map - 生产环境:
false(为了代码安全)
devtool: process.env.NODE_ENV === 'development' ? 'eval-cheap-module-source-map' : false,
又可以开心地 ✍️ 代码了!