# React Source Code Debugging [TOC] ## :whale: Build React :::info :computer: **Environment** - react `v19.0.0` - node `v20.10.0` - yarn `v1.22.22` ::: 1. 先 fork 一份 react 原始碼到自己的 github 2. 根據 [how to contribute 文件](https://legacy.reactjs.org/docs/how-to-contribute.html#development-workflow),試著把 react build 起來: ```bash= yarn yarn build react/index,react-dom/index --type=UMD ``` 3. copy `fixtures/packaging/babel-standalone/dev.html` 的路徑貼到瀏覽器網址列 上述步驟做完之後,結果失敗,頁面沒東西,無法用 debugger 且 console 有 error。研究了之後發現是因為 react 在 19 之後放棄了 UMD build,resource: - https://react.dev/blog/2024/04/25/react-19-upgrade-guide#umd-builds-removed 所以將環境更換成以下,再重複上述 1. ~ 3. 的步驟: :::info :computer: **Environment** - react [`v18.2.0`](https://github.com/facebook/react/releases/tag/v18.2.0) - node `v16.20.0` - yarn `v1.22.22` ::: 雖然還是會有以下的 error,但應該是有成功 build 起來,可以開始進行實驗: :::warning :warning: **Warning** Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot ::: 另外 chrome devTool 需要取消 enable ignore list(可以參考 https://developer.chrome.com/docs/devtools/settings/ignore-list 的去說明),也就是下面截圖的所有勾勾要取消,才能在 performance tab 看到所有在 call stack 執行過的 function: ![截圖 2024-06-29 23.18.58](https://hackmd.io/_uploads/r1WddjaLR.png) ## :whale: Using Breakpoint ### :crab: Why Breakpoint? 除了閱讀程式碼本身,使用中斷點也可以很好地幫助我們理解 code 執行的順序,尤其在一些架構比較龐大的 repo,下中斷點觀察當下的 variable 和 scope 再加上閱讀程式碼,有助於我們更快熟悉一個 repo 的架構。 ### :crab: Where to Add Breakpoint? `fixtures/packaging/babel-standalone/dev.html` 的程式碼如下: ```html= <html> <body> <script src="../../../build/node_modules/react/umd/react.development.js"></script> <script src="../../../build/node_modules/react-dom/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.js"></script> <div id="container"></div> <script type="text/babel"> ReactDOM.render( <h1>Hello World!</h1>, document.getElementById('container') ); </script> </body> </html> ``` 一個簡單的用 React render 出 Hello World 的 html 檔,用瀏覽器打開 `fixtures/packaging/babel-standalone/dev.html` 之後,觀察 `ReactDom.render` 執行後會呼叫哪些 function: ![截圖 2024-06-30 20.33.56](https://hackmd.io/_uploads/HkfhPAAIC.png) 看到最先被執行的 function 是 `getHostParentFiber`,所以先從這邊下斷點開始實驗。下斷點重新執行一次之後,可以看到完整的 call stack 順序,觀察 react 底層是如何運作: ![截圖 2024-06-30 21.16.00](https://hackmd.io/_uploads/BJHriRCUC.png) :::success :bulb: **Tips** 每個版本的 react 在 執行 `ReactDom.render` 時的 call stack 可能會不同,因為 react 會隨著版本的更新調整不同的實作方式,甚至 react 18 已經改用 `createRoot`,所以這邊的說明會以上述第一部份提到的環境為主。 ::: ## :whale: insertOrAppendPlacementNodeIntoContainer(node, before, parent) as Example 比起 `getHostParentFiber` ,後面又找到一個更適合下中斷點的 function:`insertOrAppendPlacementNodeIntoContainer`,所以在這個 function 的第一行下中斷點,看看會觸發哪些 function: ![react-source-memo(1)](https://hackmd.io/_uploads/BJa4tDUP0.png) ## :whale: Resource - [How to Contribute -React](https://legacy.reactjs.org/docs/how-to-contribute.html) - [React 19 RC Upgrade Guide - React](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) - [How does React work under the hood ? The Overview of React internals](https://jser.dev/2023-07-11-overall-of-react-internals/) - [React Internals Deep Dive 1 - Hello World! Debugging - YouTube](https://www.youtube.com/watch?v=OcB3rTln-fI&list=PLvx8w9g4qv_p-OS-XdbB3Ux_6DMXhAJC3&index=2)