如何讓調試線上 JS 報錯像調試本地源碼一樣優雅?
當線上有報錯的時候,大家是怎么定位問題的呢?
斷點調試么?
但是這時候代碼是被壓縮過的,變量名都是 a、b、c、d 這種,根本看不出啥來。
如果調試線上報錯能像本地開發的時候一樣就好了。
其實這是可以做到的,今天就分享下如何優雅的調試線上報錯:
首先,我們準備一段 JS 代碼:
這是我隨便找的一段 JS 代碼,里面拋了一個錯誤。
然后用 webpack 進行編譯:
在 index.html 里引入構建產物:
然后跑個靜態服務器 npx http-server .
瀏覽器訪問,就會發現代碼確實報錯了:
那問題來了,怎么定位錯誤原因呢?
首先,我們可以使用異常斷點,在拋異常的地方斷住:
創建一個 vscode 調試配置:
勾選 uncaught exceptions,在未被捕獲的異常處斷住:
然后啟動調試:
你會發現代碼在拋異常的地方斷住了,這就是異常斷點的功能。當你不知道哪里拋的異常的時候,可以用這個。
但現在代碼是被壓縮過的,看不出啥來:
怎么能直接定位到拋異常的源碼呢?
這時候就要用到 sourcemap 了,它就是用于把編譯后的源碼映射回源碼的:
首先要生成 sourcemap,這個配置下 webpack 的 devtool 為 hidden-source-map 即可:
hidden-source-map 的意思是生成 sourcemap 但是不關聯。
如果你配成 source-map,代碼是關聯了 sourcemap 的:
線上代碼不會這樣做。
關聯 sourcemap 需要在文件末尾加上 //# sourceMappingURL=xxx.js.map 的代碼。
但現在這個文件是線上的,不能直接改本地文件。我們可以使用 charles 的斷點功能來修改它:
charles 默認不代理 127.0.0.1 的請求,我們要配下 hosts:
比如我配了一個 www.guangtest.com 的域名到 127.0.0.1。
試一下:
hosts 配置生效了:
然后我們要讓 charles 攔截這個 url 的請求,需要安裝一個插件 SwitchyOmega
不過在那之前要指定一個數據目錄,也就是瀏覽器把插件、歷史、cookie 等數據保存在哪里:
不指定的話每次調試都會創建一個臨時數據目錄來跑調試,上次安裝的插件就沒有了。
chrome 應用商店搜索 switchy omega:
配置下代理服務器,這里我 charles 是在 127.0.0.1:8888 的:
之后配下 auto switch,讓 www.guangtest.com 的請求都走我們剛剛配的代理:
之后點擊應用選項。
代理方式設置成 auto switch,也就是根據配置的規則自動切換代理:
這個網頁的代理配成 charles 之后,在 charles 就可以抓到對應的請求了:
接下來就是斷點修改響應的內容了:
點擊 Proxy > Breakpoint Settings
添加一個對 guangtest.com 的 dist/index.js 響應的斷點:
強制刷下頁面,charles 就會斷住:
我們可以修改響應的內容,然后點擊 execute 來執行修改:
我加上了這樣一行 sourcemap 的關聯:
在 chrome devtools 里可以看到拿到的響應是被修改過的:
異常斷點現在直接在源碼處斷住了:
接下來就可以直接調試源碼了,可以通過作用域、調用棧等信息來定位報錯原因:
這樣我們就完成了直接本地調試線上報錯代碼對應的源碼!
案例代碼在:https://github.com/QuarkGluonPlasma/fe-debug-exercize。
總結
通過 sourcemap,我們可以調試線上報錯的時候直接對應到本地源碼來斷點調試。
要讓線上代碼關聯 sourcemap 可以通過 charles 斷點修改對應的響應,加上一行 sourceMappingURL=xxx 的注釋。
然后在 VSCode Debugger 里加個異常斷點,這樣就可以在異常處斷住。
這樣就可以快速定位線上錯誤的原因了,體驗就和本地開發時一樣!