有关 SourceMap 的几点个人思考
这两天在组里协助排查一个 webpack dev 环境下重载时内存溢出的问题,现象是 webpack-dev-server 启动的过程中,在 node 10.xx
的环境下,一旦修改文件工程自动 reload 时会出现内存溢出导致服务直接中断。
排查原因,最终发现原来是脚手架在配置开发环境的 devtool
配置时,为了方便开发者 DEBUG,设置成了 cheap-module-source-map
,在代码修改时触发自动 load,在 loader 编译映射 sourcemap 的时候溢~出~了~,本文不会说明为什么溢出,排查的过程以及解决,其实花的时间也不长,重点说明一下 sourcemap 的作用以及使用过程的几点个人思考。
异常
1 | [27849:0x102880000] 133250 ms: Mark-sweep 1377.8 (1409.0) -> 1377.8 (1409.5) MB, 366.7 / 0.0 ms (average mu = 0.076, current mu = 0.015) allocation failure scavenge might not succeed |
好了,上面的报错信息看过就可以忘记了。
SourceMap 在 WEB 开发过程中扮演着很重要的角色,因为被浏览器执行的代码往往与开发过程中原始代码相差很多,源码经过了很多次转译、合并、混淆、压缩等等步骤几乎不具有可读性,那么开发中调试、监控到异常定位快速与本地的源码映射匹配就成了它的唯一“使命”。
- HTTP Headers 支持
SourceMap: <url>
属性,在请求时就能将映射的资源显示在浏览器的调试面板里。 - 现代浏览器都支持加载的文件内含有类似
//# sourceMappingURL=path/to/xxx
这类注释,用来明确匹配到对应的指定文件方便跟踪。
那么在使用 SourceMap 应该注意什么呢?
可读性
要发挥它的作用,就要生成的 SourceMap 文件尽量地映射成源码,方便 debug。
比如,Webpack 的 devtool 中支持很多种生成模式,其中常用的 cheap-module-source-map
配置,就可以映射方便定位 .tsx
的内容。
平衡性能
生成 SourceMap 映射文件的过程,是一个转码的过程,记录两边的映射关系,那么转换时性能就成为了一个需要平衡的问题。理想情况,开发时尽可能保证转换速率,而构建时可以降低构建的性能消耗,保证文件的映射还原度。
预防泄漏
要避免源码泄漏,那么生成的 SourceMap 文件的存放位置就不能随意被外网访问到。
比如,异常监控系统中,为了方便开发者快速定位问题代码,在每一次构建时产生的 sourcemap 文件保存在内网指定一个位置,同时与当前上线部署版本做好匹配。
小结
在做 Java 开发时候反编译这个词应该很常见,也有对应的工具用来混淆和反混淆,WEB 端的 JavaScript / CSS 通常来说对任何人都是透明地,所以一些关键逻辑(比如涉及抽奖,特殊逻辑)尽量不要写在 js 脚本中,可以放在服务端或者编译成诸如 WebAssembly 一类字节码来避免一些重要逻辑泄漏。
PS.附赠一篇昨天无意中看到的总结,写的实在挺好的,和业界大佬还是有很大差距,加油吧。
参考文章:
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/SourceMap
- https://developer.mozilla.org/zh-CN/docs/Tools/Debugger/How_to/Use_a_source_map
- https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
- http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html
- https://webpack.docschina.org/configuration/devtool/
- https://www.timsrc.com/article/20/source-maps