UNPKG

vite-plugin-component-instrumentation

Version:

A professional Vite plugin that automatically adds identifying data attributes to React components for debugging, testing, and analytics

78 lines (77 loc) 2.52 kB
// Dev-only minimal state event publisher using React DevTools hook // Security: does not expose values; only emits component id/name placeholders // Performance: batches per-commit, idle-callback throttled const DEFAULT_CFG = { throttleMs: 120, maxItemsPerFlush: 200, }; export function setupStateEvents() { const cfg = DEFAULT_CFG; const queue = []; let scheduled = false; function enqueue(item) { queue.push(item); if (!scheduled) { scheduled = true; const schedule = window.requestIdleCallback || ((cb) => setTimeout(cb, cfg.throttleMs)); schedule(flush); } } function flush() { scheduled = false; if (!queue.length) return; const items = queue.splice(0, DEFAULT_CFG.maxItemsPerFlush); window.dispatchEvent(new CustomEvent('ct:state', { detail: { ts: Date.now(), items } })); } const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (!hook || !hook.onCommitFiberRoot) return; const original = hook.onCommitFiberRoot.bind(hook); hook.onCommitFiberRoot = function patched(rendererID, root, ...rest) { try { const current = root?.current; if (current) walk(current, (fiber) => { const node = findHostNode(fiber); if (!node) return; const id = node.getAttribute?.('data-ct-id') || node.getAttribute?.('data-debug-id'); if (!id) return; const name = node.getAttribute?.('data-ct-name') || node.getAttribute?.('data-debug-name'); enqueue({ id, name: name || undefined }); }); } catch { } return original(rendererID, root, ...rest); }; } function walk(fiber, visit) { try { visit(fiber); } catch { } let child = fiber.child; while (child) { walk(child, visit); child = child.sibling; } } function findHostNode(fiber) { // Prefer closest host child let f = fiber; while (f && !isHost(f)) f = f.child || f.sibling; if (isHost(f)) return f.stateNode; // Fallback upward f = fiber; while (f && !isHost(f)) f = f.return; return isHost(f) ? f.stateNode : null; } function isHost(f) { // HostComponent = 5, HostText = 6 return f && (f.tag === 5 || f.tag === 6) && f.stateNode instanceof Element; }