From 3cf9cc94a111f33d529ca9089fa56687b6ba3a8c Mon Sep 17 00:00:00 2001 From: Ashvini Kumar Date: Sun, 22 Jun 2025 20:35:52 +0530 Subject: [PATCH 1/2] flaky context fixed --- extension/core/mainContent/dataProcess.js | 215 +++++++++------------- 1 file changed, 86 insertions(+), 129 deletions(-) diff --git a/extension/core/mainContent/dataProcess.js b/extension/core/mainContent/dataProcess.js index c6333d0..77ce1d0 100644 --- a/extension/core/mainContent/dataProcess.js +++ b/extension/core/mainContent/dataProcess.js @@ -1,6 +1,15 @@ import { onMessage, sendMessage } from "@ext-browser/messaging/contentWindow"; import { parseData } from "./helpers"; +const IGNORED_CONTEXTS = new Set([ + "StencilProvider", + "CacheProvider", + "EmotionCacheContext", + "ThemeContext", + "StencilThemeContext", + "StencilContext", +]); + export function installHook() { let renderer = null; const reactInfo = {}; @@ -11,11 +20,11 @@ export function installHook() { const initData = { useReducer: {}, context: {}, - contextKeys: [], - useReducerKeys: [], + contextKeys: new Set(), + useReducerKeys: new Set(), }; - let fiberNodeToDebug = initData; + let fiberNodeToDebug = structuredClone(initData); onMessage("DISPATCH_USE_REDUCER_ACTION", (data) => { if ( @@ -26,16 +35,10 @@ export function installHook() { } }); - const uniqId = () => { + const uniqId = (() => { let counter = 0; - - return (prefix) => { - counter += 1; - return `${prefix} - ${counter}`; - }; - }; - - const getUniqId = uniqId(); + return (prefix) => `${prefix} - ${++counter}`; + })(); const sendDataToDevtool = () => { const dataToSend = { @@ -46,48 +49,39 @@ export function installHook() { dataToSend.context = dataToSend.contextKeys.reduce((memo, key) => { const debugObj = fiberNodeToDebug.context[key]; - - if (debugObj.valueChanged) { + if (debugObj?.valueChanged) { memo[key] = { value: parseData(debugObj.value), displayName: debugObj.displayName, }; } - return memo; }, {}); dataToSend.useReducer = dataToSend.useReducerKeys.reduce((memo, key) => { const debugObj = fiberNodeToDebug.useReducer[key]; - - if (debugObj.valueChanged) { + if (debugObj?.valueChanged) { memo[key] = { actions: debugObj.actions.map(parseData), state: debugObj.state.map(parseData), displayName: debugObj.displayName, }; } - return memo; }, {}); sendMessage("CONTEXT_DATA_UPDATED", dataToSend); }; - // /** - // * Debug for React useReducer API - // * - // * @param {object} hook - // */ const doWorkWithHooks = (hook, hookType) => { - if (hookType === "useReducer" && hook.queue.lastRenderedReducer) { + if (hookType === "useReducer" && hook.queue?.lastRenderedReducer) { let debugId = hook.queue.__reactContextDevtoolDebugId; if (!debugId) { const displayName = hook.queue.lastRenderedReducer.name; const currentReducer = hook.queue.lastRenderedReducer.bind(hook.queue); - debugId = getUniqId("useReducer"); + debugId = uniqId("useReducer"); hook.queue.__reactContextDevtoolDebugId = debugId; hook.queue.lastRenderedReducer = (state, action, ...rest) => { @@ -95,7 +89,7 @@ export function installHook() { if (debugObj && !debugObj.useDispatch) { debugObj.actions.push(action); } - currentReducer(state, action, ...rest); + return currentReducer(state, action, ...rest); }; const currentDispatch = hook.queue.dispatch.bind(hook.queue); @@ -105,7 +99,7 @@ export function installHook() { debugObj.actions.push(action); debugObj.useDispatch = true; } - currentDispatch(action, ...rest); + return currentDispatch(action, ...rest); }; fiberNodeToDebug.useReducer[debugId] = { @@ -119,7 +113,6 @@ export function installHook() { fiberNodeToDebug.useReducerKeys.add(debugId); const debugObj = fiberNodeToDebug.useReducer[debugId]; - debugObj.hook = hook; if (debugObj.state.length) { @@ -127,8 +120,8 @@ export function installHook() { debugObj.state[debugObj.state.length - 1] !== hook.queue.lastRenderedState; debugObj.valueChanged = valueChanged; + if (!valueChanged) { - // action dispatched but return same state or wrong state handling const diff = debugObj.actions.length - debugObj.state.length; if (diff > 0) { for (let i = 0; i < diff; i++) { @@ -144,25 +137,26 @@ export function installHook() { } }; - // /** - // * Debug for React Context API - // * - // * @param {object} node - // */ const doWorkWithContextProvider = (node) => { - if (!node.type) { - return; - } + if (!node.type) return; - // React 18: node.type._context - // React 19: node.type (context is directly on the type) const context = node.type._context || node.type; - if (!context.__reactContextDevtoolDebugId) { - context.__reactContextDevtoolDebugId = getUniqId("context"); + context.__reactContextDevtoolDebugId = uniqId("context"); } const debugId = context.__reactContextDevtoolDebugId; + + const displayName = + node.pendingProps.displayName || + context.displayName || + (node._debugOwner?.elementType?.name + ? `Child Of ${node._debugOwner?.elementType?.name}` + : null) || + debugId; + + if (IGNORED_CONTEXTS.has(displayName)) return; + fiberNodeToDebug.contextKeys.add(debugId); const valueChanged = !( @@ -173,49 +167,30 @@ export function installHook() { fiberNodeToDebug.context[debugId] = { valueChanged, value: node.pendingProps.value, - displayName: - node.pendingProps.displayName || - context.displayName || - (node._debugOwner?.elementType?.name - ? `Child Of ${node._debugOwner?.elementType?.name}` - : null) || - debugId, + displayName, }; }; - // /** - // * Find supported element and attach devtool - // * - // * @param {object} fiberNode - // */ const doWorkWithFiberNode = (fiberNode) => { - if (!fiberNode) { - return; - } + if (!fiberNode) return; const { memoizedState, tag, _debugHookTypes } = fiberNode; if ( settings.debugUseReducer && - _debugHookTypes && - _debugHookTypes.length && + _debugHookTypes?.length && memoizedState && - Object.hasOwnProperty.call(memoizedState, "baseState") + Object.prototype.hasOwnProperty.call(memoizedState, "baseState") ) { let temp = memoizedState; - const hookTypes = _debugHookTypes || []; let counter = 0; while (temp && temp.queue) { - doWorkWithHooks(temp, hookTypes[counter]); + doWorkWithHooks(temp, _debugHookTypes[counter]); temp = temp.next; counter += 1; } } - /** - * https://github.com/facebook/react/tree/master/packages/react-reconciler/src/ReactWorkTags.js - * - */ if (settings.debugContext && tag === 10) { doWorkWithContextProvider(fiberNode); } @@ -224,48 +199,50 @@ export function installHook() { const debounce = (func, wait, immediate) => { let timeout; return function () { - const context = this; - const args = arguments; + const context = this, + args = arguments; const later = function () { timeout = null; - if (!immediate) { - func.apply(context, args); - } + if (!immediate) func.apply(context, args); }; const callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); - if (callNow) { - func.apply(context, args); - } + if (callNow) func.apply(context, args); }; }; const onCommitFiberRoot = (reactFiberRoot) => { - if (!settings.debugUseReducer && !settings.debugContext) { - return; - } - - if (!enabled) { - return null; - } + if (!settings.debugUseReducer && !settings.debugContext) return; + if (!enabled) return; try { - function traverseFiberTree(node) { - if (!node) { - return null; - } - doWorkWithFiberNode(node); + const newState = { + context: {}, + useReducer: {}, + contextKeys: new Set(), + useReducerKeys: new Set(), + }; + const traverseFiberTree = (node) => { + if (!node) return; + const prev = fiberNodeToDebug; + fiberNodeToDebug = newState; + doWorkWithFiberNode(node); traverseFiberTree(node.sibling); traverseFiberTree(node.child); - } - - fiberNodeToDebug.contextKeys = new Set(); - fiberNodeToDebug.useReducerKeys = new Set(); + fiberNodeToDebug = prev; + }; traverseFiberTree(reactFiberRoot.current); + if ( + newState.contextKeys.size > 0 || + newState.useReducerKeys.size > 0 + ) { + fiberNodeToDebug = newState; + } + sendDataToDevtool(); } catch (err) { if (err.message !== "Maximum call stack size exceeded") { @@ -277,40 +254,24 @@ export function installHook() { const onCommit = debounce(onCommitFiberRoot, 100, true); const debugFiber = (params) => { - const reactDebtoolGlobalhook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; - + const reactHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; renderer = params.renderer; - reactInfo.version = renderer ? renderer.version : ""; - reactInfo.rendererPackageName = renderer - ? renderer.rendererPackageName - : ""; + reactInfo.version = renderer?.version || ""; + reactInfo.rendererPackageName = renderer?.rendererPackageName || ""; - fiberRoot = reactDebtoolGlobalhook - .getFiberRoots(params.id) - .keys() - .next().value; + fiberRoot = reactHook?.getFiberRoots(params.id)?.keys()?.next()?.value; if (fiberRoot) { onCommitFiberRoot(fiberRoot); } - /** - * Register react dom commit fiber callback - * - */ - if ( - reactDebtoolGlobalhook && - typeof reactDebtoolGlobalhook.onCommitFiberRoot === "function" - ) { - reactDebtoolGlobalhook.onCommitFiberRoot = ( - (debugFunction) => - (rendererID, root, ...args) => { - fiberRoot = root; - onCommit(root); - return debugFunction(rendererID, root, ...args); - } - )(reactDebtoolGlobalhook.onCommitFiberRoot); + if (typeof reactHook.onCommitFiberRoot === "function") { + reactHook.onCommitFiberRoot = ((debugFn) => (rendererID, root, ...args) => { + fiberRoot = root; + onCommit(root); + return debugFn(rendererID, root, ...args); + })(reactHook.onCommitFiberRoot); } }; @@ -322,21 +283,19 @@ export function installHook() { return false; } - const reactDebtoolGlobalhook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; + const reactHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; + const firstKey = reactHook.renderers?.keys()?.next()?.value; - const firstRendererKey = reactDebtoolGlobalhook.renderers - .keys() - .next().value; - - debugFiber({ - id: firstRendererKey, - renderer: reactDebtoolGlobalhook.renderers.get(firstRendererKey), - }); + if (firstKey) { + debugFiber({ + id: firstKey, + renderer: reactHook.renderers.get(firstKey), + }); + } }; const startDebug = () => { enabled = true; - if (fiberRoot) { onCommitFiberRoot(fiberRoot); } @@ -344,13 +303,11 @@ export function installHook() { const stopDebug = () => { enabled = false; - fiberNodeToDebug = initData; + fiberNodeToDebug = structuredClone(initData); }; const setSettings = (newSettings) => { - if (newSettings) { - settings = newSettings; - } + if (newSettings) settings = newSettings; }; return { From 1b20024658b4db06841a014f224f82ca08a4afb7 Mon Sep 17 00:00:00 2001 From: Ashvini Kumar Date: Sun, 22 Jun 2025 20:56:33 +0530 Subject: [PATCH 2/2] BFW specific context sorting --- extension/core/mainContent/dataProcess.js | 42 +++++++++++++++++------ 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/extension/core/mainContent/dataProcess.js b/extension/core/mainContent/dataProcess.js index 77ce1d0..eca51eb 100644 --- a/extension/core/mainContent/dataProcess.js +++ b/extension/core/mainContent/dataProcess.js @@ -47,7 +47,20 @@ export function installHook() { useReducerKeys: [...fiberNodeToDebug.useReducerKeys], }; - dataToSend.context = dataToSend.contextKeys.reduce((memo, key) => { + const sortedContextKeys = [...fiberNodeToDebug.contextKeys].sort((a, b) => { + const nameA = fiberNodeToDebug.context[a]?.displayName || ""; + const nameB = fiberNodeToDebug.context[b]?.displayName || ""; + + const isBFW_A = nameA.startsWith("BFW_"); + const isBFW_B = nameB.startsWith("BFW_"); + + if (isBFW_A && !isBFW_B) return -1; + if (!isBFW_A && isBFW_B) return 1; + + return nameA.localeCompare(nameB); + }); + + dataToSend.context = sortedContextKeys.reduce((memo, key) => { const debugObj = fiberNodeToDebug.context[key]; if (debugObj?.valueChanged) { memo[key] = { @@ -155,6 +168,15 @@ export function installHook() { : null) || debugId; + // console.log("\n node.pendingProps>>", node.pendingProps); + // console.log("\n context>>", context); + // console.log("\n node._debugOwner>>", node._debugOwner); + // console.log( + // "\n debugId>>", + // debugId, + // "\n---------------------------------------\n", + // ); + if (IGNORED_CONTEXTS.has(displayName)) return; fiberNodeToDebug.contextKeys.add(debugId); @@ -236,10 +258,7 @@ export function installHook() { traverseFiberTree(reactFiberRoot.current); - if ( - newState.contextKeys.size > 0 || - newState.useReducerKeys.size > 0 - ) { + if (newState.contextKeys.size > 0 || newState.useReducerKeys.size > 0) { fiberNodeToDebug = newState; } @@ -267,11 +286,14 @@ export function installHook() { } if (typeof reactHook.onCommitFiberRoot === "function") { - reactHook.onCommitFiberRoot = ((debugFn) => (rendererID, root, ...args) => { - fiberRoot = root; - onCommit(root); - return debugFn(rendererID, root, ...args); - })(reactHook.onCommitFiberRoot); + reactHook.onCommitFiberRoot = ( + (debugFn) => + (rendererID, root, ...args) => { + fiberRoot = root; + onCommit(root); + return debugFn(rendererID, root, ...args); + } + )(reactHook.onCommitFiberRoot); } };