react-devtools-inline をアプリに入れ込んでHTMLElementからFiberを取得する
更新日:2022年8月8日

前回の記事の続きです。
React Developer Tools がどのようにソースコードを特定しているのかわかりました。
Fiberの中に情報が入っており、HTMLElementからFiberは取得できます。
ということは react-devtoolsのバックエンドが動いている場合に、HTMLElementからReactコンポーネントのソースコードがわかるということです。
なので、今回はReact Devtoolsを組み込める。
react-devtools-inline を使って任意のWebアプリのHTMLElementからFiberを取得することができるのかということをやっていきます。
というか react-devtools-inline のREADMEを読んで初期化しているがうまく動かない。なぜ?
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ に値が入っているはずなのだが...
とりあえず、 スタンドアロン版 があるのでそれで進める。
なんとなくやりたいことができた。 ホバーしたコンポーネントのソース位置を表示して、VsCodeで開くことができる。

事前の準備としては、下記の2つが必要 ソースを調査したいアプリのルートで下記のコマンドでスタンドアロン版のReact dev toolsを起動しておく。
1
npx react-devtools
また、下記のコードをソースを調査したいアプリのHTMLで読み込んでおく。
2
const devToolsScript = document.createElement("script");
devToolsScript.setAttribute("src", "http://localhost:8097");
document.head.appendChild(devToolsScript);
const init = () => {
let tmpBoder = "";
window.addEventListener("pointerout", (e) => {
if (!e.target || !window.__REACT_DEVTOOLS_GLOBAL_HOOK__) return;
e.target.style.border = tmpBoder;
});
window.addEventListener("pointerover", (e) => {
if (!e.target || !window.__REACT_DEVTOOLS_GLOBAL_HOOK__) return;
const renderer = window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.get(1);
if (!renderer) return;
tmpBoder = e.target.style.border;
const fiber = renderer.findFiberByHostInstance(e.target);
if (fiber && fiber._debugSource) {
e.target.style.border = "1px solid blue";
window.parent.postMessage(
{ source: "tailwind-editor", _debugSource: fiber._debugSource },
"*"
);
}
});
};
devToolsScript.addEventListener("load", init);
やっていることはホバーしている要素からFiberを取得できたらソースコードの情報をpostMessageを通じて親のWindowに通信している。
親のWindowはこの調査したいアプリをiframeとして読み込んでおり、ソースコードが送られてくるので、ツールチップで表示しているだけ。
最終的にはこれはVsCodeのエクステンションに送られる想定。
次は送られた値を使ってファイルを読み込みBabelで解析してclassNameを取得する処理を書く