<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
什麼?偵錯 React 原始碼還有優雅和不優雅之分?
彆著急,我們先來聽個故事:
東東是一名前端工程師,主要用 React 技術棧,用了多年之後想深入一下,所以最近開始看 React 原始碼。
他把 react 和 react-dom 包下載了下來,在專案裡引入,開發服務跑起來後,開啟 Chrome Devtools 打斷點偵錯。
這樣偵錯了一段時間之後,他有了一些困惑:
這樣偵錯是可以的,但是總感覺和原始碼有段距離,因為偵錯的是 react-dom.development.js
而原始碼裡這些邏輯是分散在不同的包裡的,所以就算搞懂了邏輯,也不知道這些邏輯在哪些包裡,只能靠搜尋來定位。
所以他就在想,是不是有更好的偵錯方式,能夠偵錯 React 最初的原始碼呢?
於是,他跑來問我:光哥,你偵錯 React 原始碼會有這些問題麼?你是怎麼偵錯的呀?
我說,確實,我最開始也是偵錯的 react-dom.development.js,但是現在已經能直接偵錯 React 最初的原始碼了,而且是在 VSCode 裡偵錯的,點選呼叫棧能直接開啟對應的 React 原始碼檔案並定位到對應行列號:
哇哦,這就是我想要的偵錯效果,這是怎麼做到的呀。
想實現這樣的偵錯效果確實還有點複雜,我們一點點來看:
首先,我們要做到在 VSCode 裡偵錯 React 專案,而不是在 Chrome Devtools 裡,這樣才能做到直接開啟對應的檔案:
用 VSCode 偵錯 React 專案
我們用 create-react-app 建立一個 react 專案,然後 npm run start 跑起來。
這時候瀏覽器存取就可以用 Chrome Devtools 偵錯了:
但我們的目標是在 VSCode 裡偵錯,所以要新增一個 VSCode 的 debugger 設定:
在根目錄下建一個 .vscode/launch.json 的檔案,新增一個 chrome 型別的偵錯設定,輸入偵錯的 url。
然後點選 debug 啟動:
這時候就可以在 VSCode 裡直接打斷點偵錯了:
用 VSCode 偵錯肯定會比 Chrome Devtools 方便一些。但這不是我們最主要的目的,現在偵錯的依然是 react-dom.development.js:
那怎麼偵錯 react 最初的原始碼呢?
這就涉及到 sourcemap 的作用了:
JS 程式碼經過編譯,會產生目的碼,但同時也會產生 sourcemap。sourcemap 的作用就是對映目的碼中的位置和原始碼中的位置。
比如原始碼中的第 3 行第 5 列的程式碼對應著編譯後的第 1 行第 10 列的程式碼。
類似這樣的對映有很多,經過編碼以後是這樣的:
在 js 檔案最後一行,加上這樣一行註釋就可以關聯 sourcemap:
//# sourceMappingURL=http://example.com/path/to/your/sourcemap.map
偵錯工具支援解析 sourcemap 來對映偵錯的程式碼位置到原始碼中的位置。
比如 chrome devtools 的 Sources 面板就會提示從哪個檔案 source mapping 過來的,點選連結還可以跳到對映之前的檔案:
同樣,VSCode Debugger 也支援 sourcemap,有個 sourceMaps 的偵錯設定選項來開啟和關閉 sourcemap 功能,預設開啟。
那這麼說我們只要讓 react-dom.development.js 關聯上 sourcemap,就能偵錯最初的 React 原始碼了?
理論上是這樣的,但是現在下載的 react、react-dom 包裡都不帶 sourcemap,我們得把 React 原始碼下載下來自己 build:
build 出帶有 sourcemap 的 react 包
用 npm 下載的 react 包是這樣的:
而我們需要的是帶有 sourcemap 的程式碼,也就是這樣的:
這就要下載 react 原始碼自己 build 了:
git clone https://github.com/facebook/react
下載下來的程式碼執行 npm run build 就能看到 build 的產物:
這裡的 build/node_modules 下的 react 和 react-dom 包就是我們需要的。
但是現在 build 出的程式碼並沒有帶 sourcemap,需要改造下 build 流程。
build 命令執行的是 ./scripts/rollup/build.js,開啟這個檔案做一些修改。
找到 rollup 的設定,新增一行 sourcemap: true,這個很容易理解,就是讓 rollup 在構建時產生 sourcemap:
再跑 npm run build,會報這樣的錯誤:
某個轉換的外掛沒有生成 sourcemap。
這個是因為構建的過程中會進行多次轉換,會生成多次 sourcemap,然後把 sourcemap 串聯起來就是最終的 sourcemap。如果中間有一步轉換沒有生成 sourcemap,那就斷掉了,也就沒法把 sourcemap 串聯起來了。
這個問題的解決只要找出沒有生成 sourcemap 的那幾個外掛註釋掉就可以了:
在 getPlugins 方法裡,把這樣 4 個外掛給註釋掉:
這個是刪除 use strict 用的,可以去掉。
這個是生產環境壓縮程式碼的,也可以去掉。
這個是用 prettier 格式化程式碼的,也可以去掉。
這個是新增一些頭部的程式碼的,比如 Lisence 等,也沒啥用,可以去掉。
去掉這四個外掛之後,再執行 npm run build,這時候就能正常進行構建了,然後產生的程式碼就是帶有 sourcemap 的:
這樣我們就成功的 build 出了帶有 sourcemap 的 react 包!
接下來只剩最後一步,用上 sourcemap,實現直接偵錯 React 最初的原始碼,
應用 sourcemap,偵錯 React 最初的原始碼
我們已經 build 除了帶有 sourcemap 的 react 和 react-dom 包,那把這倆包複製到測試專案的 node_modules 下,就可以直接偵錯最初的原始碼了麼?
還是不行。
為什麼呢?
看下面這張圖:
我們改造了 build 流程,對 react 原始碼進行了 build,產生了帶有 sourcemap 的 react、react-dom 包,這些包最終匯出的是 react-xx.development.js。
之後在專案裡引入,經過 webpack 打包,產生了 bundle.js 和 sourcemap。
之後偵錯工具執行程式碼的時候,會解析 sourcemap,完成從 bundle.js 到 react-xxx.development.js 的對映:
但是並不會再次做 react-xx.development.js 到 react 最初原始碼的對映呀。
也就是偵錯工具只會解析一次 sourcemap。
那怎麼辦呢?
不打包 react 和 react-dom 這倆包不就行了。不經過 webpack 打包,那就沒有 webpack 產生的 sourcemap,不就一次就對映到 React 最初的原始碼了麼。
那怎麼不打包這倆模組呢?
webpack 支援 externals 來設定一些模組使用全域性變數而不進行打包,這樣我們就可以單獨載入 react、react-dom,然後把他們匯出的全域性變數設定到 externals 就行了。
要改動 webpack 設定的話,在 create-react-app 下要執行 npm run eject。
然後專案下會多出 config 目錄和 public 目錄,這倆分別放著 webpack 設定和一些公共檔案。
修改 webpack 設定,在 externals 下新增 react 和 react-dom 包對應的全域性變數:
然後把 react.development.js 和 react-dom.development.js 放到 public 下,並在 index.html 裡面載入這倆檔案:
這樣再重新 debug,你就會發現 sourcemap 對映到 React 最初的原始碼了:
不再是 react-dom.development.js 下的程式碼,而是具體 react-xxx 包下的。
這就達到了最開始的目的,能直接偵錯 React 最初的原始碼!
還記得我們這樣做的意義麼?
能偵錯最初的原始碼才能知道哪段邏輯是在哪個包裡的,不然要自己去搜尋。
這樣已經能夠達到我們的目的了,但是要想點選呼叫棧直接定位到 git clone 下來的 react 專案的檔案,還需要再做一步。
看我最初演示的效果,點選呼叫棧是能直接定位到 react 原始碼專案的檔案的:
這是怎麼做到的呢?
其實只要 sourcemap 生效,並且 map 到的檔案是在當前 workspace 下,VSCode 就會開啟對應的檔案。
現在 sourcemap 已經生效了,只不過 react 專案沒有在 workspace 下。所以,如果想直接定位 react 原始碼專案的話,可以這樣做:
建立一個新的目錄,把 react 原始碼專案和測試的專案放到一個 workspace 下,這樣再偵錯的時候,map 到的檔案就能在 workspace 找到了,也就會開啟相應的檔案。
只不過現在 sourcemap 下都是這樣的相對路徑,會導致對映到的檔案路徑不對:
所以再去修改下 react build 流程,在 ./script/rollup/build.js 下,新增一個 sourcemap 的路徑對映,把 ../../../packages 對映到 react 專案的絕對路徑/pcakges :
這時候再重新 build,生成的 sourcemap 就是絕對路徑了:
把新生成的 sourcemap 複製過去,覆蓋一下。
在新的 workspace 裡 debug,你就會發現,路徑對映對了:
點選呼叫棧能直接開啟 react 原始碼專案的對應檔案了!
至此,我們就能優雅的偵錯 React 最初的原始碼了。
用了 react 比較長時間後,自然會想偵錯下原始碼來深入下,但是常規的偵錯方式只能偵錯 react-dom.development.js,雖然能理清邏輯,但是對應不到原始碼裡的哪些包哪些檔案,總感覺和最初的原始碼還有一段距離。
這個問題是有解決方案的,就是會有點複雜:
首先要把 react 原始碼專案下載下來,修改 build 流程來生成帶有 sourcemap 的 react 和 react-dom 包,並且修改 sourcemap 對映的路徑為絕對路徑。
然後把 react 和 react-dom 設定到 webpack 的 externals 裡,不進行打包,而是單獨在 index.html 裡引入。
因為 sourcemap 只會對映一次,而 webpack 已經生成了一次 sourcmap,只有跳過這倆模組的打包才能讓 react 和 react-dom 的 sourcemap 生效。
之後用 VSCode Debugger 來偵錯 React 專案,就能對映到最初的 React 原始碼了。
如果想點選呼叫棧直接開啟對應 React 原始碼專案的檔案,那就新建一個 workspace,把測試專案和 React 原始碼專案包含就行了。因為 VSCode 如果在 workspace 下找到了 source map 到的檔案,就會直接開啟對應的檔案。
東東:最終的偵錯效果是很完美,但這個流程有點複雜
我:確實,想實現能偵錯最初的原始碼,並且還能直接開啟對應的 react 原始碼專案的檔案,還是比較麻煩的,但好在只需要設定一次,以後就能一直用了,而且類似的原始碼偵錯方式也可以應用到其他原始碼的偵錯。
毫不誇張地說,這應該是全網最優雅的 React 原始碼偵錯方式了。
以上就是React 原始碼偵錯方式的詳細內容,更多關於React 原始碼偵錯的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45