From 9cd41a0771e4d174fb3ba21fcc1879d8f4ee709b Mon Sep 17 00:00:00 2001 From: YvanoffP Date: Tue, 3 Feb 2026 14:11:33 +0100 Subject: [PATCH 1/2] fix: check all fibers instead of hardcoding the first --- src/utils.ts | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index e719946..a1fafbd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -16,34 +16,54 @@ export const checkDevtoolsGlobalHook = (): boolean => window.__REACT_DEVTOOLS_GLOBAL_HOOK__ && window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers && window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.size > 0 && - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.get(1); - -// TODO Refactoring needed ref react/packages/react-devtools-shared/src/backend/agent.js getBestMatchingRendererInterface -const getDevtoolsGlobalHookRenderer = () => { - if (!checkDevtoolsGlobalHook()) return null; - return window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.get(1); -}; + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.values().length > 0; export const findFiberByHostInstance = ( target: HTMLElement ): { _debugSource: DebugSource } | null => { if (!checkDevtoolsGlobalHook()) return null; + const renderers = window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers; + + // Try all available renderers + for (const [, renderer] of renderers.entries()) { + if (!renderer?.findFiberByHostInstance) continue; + + const fiber = renderer.findFiberByHostInstance(target); + if (fiber && fiber._debugSource) { + return fiber; + } + } + + return null; +}; - const renderer = getDevtoolsGlobalHookRenderer(); - if (!renderer) return null; +export const applyPathMappings = (path: string, pathMappings: string): string => { + if (!path || !pathMappings) return path; - const fiber = renderer.findFiberByHostInstance(target) || null; + const lines = pathMappings.split('\n'); + for (const line of lines) { + const trimmed = line.trim(); + if (!trimmed) continue; - return fiber && fiber._debugSource ? fiber : null; + const [from, to] = trimmed.split('|'); + if (from && to && path.startsWith(from.trim())) { + return path.replace(from.trim(), to.trim()); + } + } + + return path; }; export const getEditorLink = ( openInEditorUrl: string, - debugSource: DebugSource + debugSource: DebugSource, + pathMappings: string = '' ) => { - const { fileName, columnNumber, lineNumber } = debugSource; + const { columnNumber, lineNumber } = debugSource; + const fileName = applyPathMappings(debugSource.fileName || '', pathMappings); + return openInEditorUrl - .replace("{path}", fileName || "") + .replace("{path}", fileName) .replace("{line}", lineNumber ? lineNumber.toString() : "0") .replace("{column}", columnNumber ? columnNumber.toString() : "0"); }; From 94bddf5e2d1d1abd04637dbee4e5924a05f11fce Mon Sep 17 00:00:00 2001 From: YvanoffP Date: Tue, 3 Feb 2026 14:11:38 +0100 Subject: [PATCH 2/2] chore: add pathmapping to options and code --- src/content-main-world.ts | 4 +++- src/content.ts | 2 +- src/options.html | 9 +++++++++ src/options.ts | 18 ++++++++++++------ 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/content-main-world.ts b/src/content-main-world.ts index 79ac6d1..1020107 100644 --- a/src/content-main-world.ts +++ b/src/content-main-world.ts @@ -11,6 +11,7 @@ let inspecting = false; let openInEditorUrl = DEFAULT_OPEN_IN_EDITOR_URL; const mousePos = { x: 0, y: 0 }; let openInEditorMethod = 'url'; +let pathMappings = ''; const getInspectName = (element: HTMLElement) => { const fiber = findFiberByHostInstance(element); @@ -74,7 +75,7 @@ const handleInspectorClick = async (e: MouseEvent) => { target.id = tmpId; window.postMessage("inspected", "*"); - const deepLink = getEditorLink(openInEditorUrl, fiber._debugSource) + const deepLink = getEditorLink(openInEditorUrl, fiber._debugSource, pathMappings) if(openInEditorMethod === 'fetch'){ fetch(deepLink); }else{ @@ -101,6 +102,7 @@ window.addEventListener("message", ({ data }) => { if (data.type === "options" && data.openInEditorUrl) { openInEditorUrl = data.openInEditorUrl; openInEditorMethod = data.openInEditorMethod; + pathMappings = data.pathMappings || ''; } }); diff --git a/src/content.ts b/src/content.ts index 540c89b..9d56c12 100644 --- a/src/content.ts +++ b/src/content.ts @@ -11,7 +11,7 @@ script.onload = () => { if (request === "inspect") { window.postMessage(request, "*"); chrome.storage.sync.get( - { openInEditorUrl: DEFAULT_OPEN_IN_EDITOR_URL, openInEditorMethod:'url' }, + { openInEditorUrl: DEFAULT_OPEN_IN_EDITOR_URL, openInEditorMethod:'url', pathMappings: '' }, (items) => { window.postMessage({ type: "options", ...items }, "*"); } diff --git a/src/options.html b/src/options.html index 6b5b312..e2bbba5 100644 --- a/src/options.html +++ b/src/options.html @@ -125,6 +125,15 @@

React Inspector Options

+
diff --git a/src/options.ts b/src/options.ts index 049a9b9..dc6ee1c 100644 --- a/src/options.ts +++ b/src/options.ts @@ -7,26 +7,32 @@ const getElements = () => { const openInEditorMethod = document.getElementById('open-in-editor-method') as HTMLSelectElement; - return {openInEditorUrl,openInEditorMethod} + const pathMappings = document.getElementById('path-mappings') as HTMLTextAreaElement; + + return {openInEditorUrl, openInEditorMethod, pathMappings} } const initOptions = () => { - - const { openInEditorUrl, openInEditorMethod } = getElements(); + const { openInEditorUrl, openInEditorMethod, pathMappings } = getElements(); chrome.storage.sync.get( - { openInEditorUrl: DEFAULT_OPEN_IN_EDITOR_URL, openInEditorMethod:'url' }, + { openInEditorUrl: DEFAULT_OPEN_IN_EDITOR_URL, openInEditorMethod:'url', pathMappings: '' }, (items) => { openInEditorUrl.value = items.openInEditorUrl; openInEditorMethod.value = items.openInEditorMethod; + pathMappings.value = items.pathMappings; } ); }; const saveOptions = (feedbackMsg: string) => { - const { openInEditorUrl, openInEditorMethod } = getElements(); + const { openInEditorUrl, openInEditorMethod, pathMappings } = getElements(); - chrome.storage.sync.set({ openInEditorUrl: openInEditorUrl.value, openInEditorMethod:openInEditorMethod.value }, () => { + chrome.storage.sync.set({ + openInEditorUrl: openInEditorUrl.value, + openInEditorMethod: openInEditorMethod.value, + pathMappings: pathMappings.value + }, () => { const status = document.getElementById("status")!; status.textContent = feedbackMsg; setTimeout(() => {