From 006894274eddc4a414232b63270c44a27cdf20c4 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Mon, 20 Apr 2026 11:16:21 +0700 Subject: [PATCH] fix(desktop): patch React DevTools manifest for Electron compatibility --- .../desktop/src/features/react-devtools.ts | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/packages/desktop/src/features/react-devtools.ts b/packages/desktop/src/features/react-devtools.ts index 7c16e7a46..19f453406 100644 --- a/packages/desktop/src/features/react-devtools.ts +++ b/packages/desktop/src/features/react-devtools.ts @@ -1,10 +1,68 @@ import path from "node:path"; import { existsSync } from "node:fs"; -import { mkdir, writeFile, unlink } from "node:fs/promises"; +import { mkdir, readFile, writeFile, unlink } from "node:fs/promises"; import { app, session, net } from "electron"; const REACT_DEVTOOLS_EXTENSION_ID = "fmkadmapgofadopljbjfkapdkoienihi"; +type ReactDevToolsContentScript = { + matches: string[]; + js: string[]; + run_at: "document_start" | "document_end"; + world?: "MAIN"; +}; + +type ReactDevToolsManifest = { + version?: string; + manifest_version?: number; + content_scripts?: ReactDevToolsContentScript[]; +}; + +const ELECTRON_COMPATIBLE_CONTENT_SCRIPTS: ReactDevToolsContentScript[] = [ + { + matches: [""], + js: ["build/proxy.js"], + run_at: "document_start", + }, + { + matches: [""], + js: ["build/installHook.js"], + run_at: "document_start", + world: "MAIN", + }, + { + matches: [""], + js: ["build/hookSettingsInjector.js"], + run_at: "document_start", + }, + { + matches: [""], + js: ["build/fileFetcher.js"], + run_at: "document_end", + }, +]; + +function hasStaticReactHookScript(manifest: ReactDevToolsManifest): boolean { + return ( + manifest.content_scripts?.some((script) => script.js.includes("build/installHook.js")) ?? false + ); +} + +async function patchReactDevToolsForElectron(extensionPath: string): Promise { + const manifestPath = path.join(extensionPath, "manifest.json"); + const manifest = JSON.parse(await readFile(manifestPath, "utf-8")) as ReactDevToolsManifest; + + if (manifest.manifest_version !== 3 || hasStaticReactHookScript(manifest)) { + return; + } + + // React DevTools v7 relies on chrome.scripting.registerContentScripts, + // which Electron does not reliably inject into app pages. Static scripts do. + manifest.content_scripts = ELECTRON_COMPATIBLE_CONTENT_SCRIPTS; + await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + console.log(`[DevTools] Patched React DevTools ${manifest.version} content scripts for Electron`); +} + export async function loadReactDevTools(): Promise { const extensionsDir = path.join(app.getPath("userData"), "extensions"); const extensionPath = path.join(extensionsDir, REACT_DEVTOOLS_EXTENSION_ID); @@ -33,6 +91,7 @@ export async function loadReactDevTools(): Promise { } try { + await patchReactDevToolsForElectron(extensionPath); const ext = await session.defaultSession.extensions.loadExtension(extensionPath, { allowFileAccess: true, });