1. 程式人生 > 其它 >記一次react-devtools探索過程

記一次react-devtools探索過程

為什麼要探究react-devtools?這一切都要源於一次痛苦的看程式碼過程,
剛來位元組的時候,要熟悉接觸公司內部的業務程式碼,剛開始是通過修復一些元件的簡單bug來上手熟悉,
上手熟悉就得先找到這個元件的檔案位置,但專案中元件的層層巢狀讓我難以找到具體位置,以至於頁面上隨便一個按鈕,找到它的位置就要花費一段時間了。

那麼,我們能不能自動化這個找的過程呢?回答是:可以,不過這是馬後炮了,筆者在這中途的調研過程中,經歷了很多曲折。

開始研究react-devtool

猜測可能react-devtool可能已經有跟蹤元件檔案位置的功能,因此一開始,我去把react-devtool上的所有按鈕都點了一遍,最終在view source功能按鈕上發現了可能的解決問題的可能

點選之後chrome的開發者工具跳轉到了原始碼標籤,並標識了按鈕渲染函式的位置

好傢伙,這和我想做的跟蹤檔案位置已經很接近了,不僅如此,看下方“第442行,第23列(從xxx.js)”對映到原始碼
綜上,我能明確發現view source這個功能的能力有:
1.獲取元件的渲染函式
2.跳轉到渲染函式的所在位置
3.可以獲取到檔案位置路徑和其所在的行和列
接下來就讓我們來驗證這三個能力是如何實現的。
因此筆者馬不停蹄的在github上搜索react devtools的開原始碼

react-devtool view source 原始碼

  const viewElementSourceFunction = id => {
          const rendererID = store.getRendererIDForElement(id);
          if (rendererID != null) {
            // Ask the renderer interface to determine the component function,
            // and store it as a global variable on the window
            bridge.send('viewElementSource', {id, rendererID});

            setTimeout(() => {
              // Ask Chrome to display the location of the component function,
              // or a render method if it is a Class (ideally Class instance, not type)
              // assuming the renderer found one.
              chrome.devtools.inspectedWindow.eval(`
                if (window.$type != null) {
                  if (
                    window.$type &&
                    window.$type.prototype &&
                    window.$type.prototype.isReactComponent
                  ) {
                    // inspect Component.render, not constructor
                    inspect(window.$type.prototype.render);
                  } else {
                    // inspect Functional Component
                    inspect(window.$type);
                  }
                }
              `);
            }, 100);
          }
        };

關鍵點在於chrome.devtools.inspectedWindow.eval這個api,其中執行了inspect(window.$type.prototype.render)
window.$type.prototype.render便是元件的渲染函式,具體是怎麼被註冊到全域性window上的,後面會提到。
現在我們先來具體講講inspect這個瀏覽器api,
很簡單,我們做個實驗就懂了,首先在控制檯輸入這行程式碼

let p=document.querySelector('p');
inspect(p);

執行了之後,我們會驚奇的發現,它從控制檯跳轉到了元素,並標識了p標籤所在的位置。

那,如果inspect的入參不是dom而是一個函式呢?

function func(){}
inspect(func)

這時候神奇的事情來了,控制檯跳轉到了函式a的定義位置,

現在我們再來說說window.$type到底是什麼東西。