UNPKG

react-beetle-inspector

Version:

Debug re-renders, API calls and performance issues in React apps with an overlay.

226 lines (225 loc) 8.01 kB
import r, { useRef as h, useEffect as x, useState as y, useLayoutEffect as O } from "react"; function W(n, e) { return JSON.stringify(n) === JSON.stringify(e); } const D = /* @__PURE__ */ new Map(), X = () => [...D.entries()].sort((n, e) => e[1] - n[1]).slice(0, 5), F = (n, e = {}) => { const o = h(e), a = h(1); x(() => { if (process.env.NODE_ENV !== "development") return; const l = Object.entries(e).reduce((m, [d, f]) => (W(f, o.current[d]) || (m[d] = { from: o.current[d], to: f }), m), {}), u = n || "Unknown"; D.set(u, (D.get(u) || 0) + 1), console.groupCollapsed( `%c[${u}] Render #${a.current}`, "color: dodgerblue;" ), Object.keys(l).length === 0 ? console.log("No prop changes.") : console.log("Changed Props:", l), console.trace(`[${u}] render trace`), console.groupEnd(), o.current = e, a.current += 1; }); }, E = [], Y = 100; let R = []; const j = () => { R.forEach((n) => n([...E])); }, M = (n) => (R.push(n), n([...E]), () => { R = R.filter((e) => e !== n); }), C = ({ url: n, method: e, duration: o, status: a, stack: l }) => { E.length > Y && E.shift(), E.push({ url: n, method: e, duration: o, status: a, time: /* @__PURE__ */ new Date(), stack: l }), j(); }, U = () => { if (typeof window > "u") return; const n = window.fetch; window.fetch = async (...e) => { var m; const o = e[0], a = (((m = e[1]) == null ? void 0 : m.method) || "GET").toUpperCase(), l = performance.now(), u = new Error().stack.split(` `).slice(2, 6).join(` `); try { const d = await n(...e), f = (performance.now() - l).toFixed(2); return C({ url: o, method: a, duration: f, status: d.status, stack: u }), d; } catch (d) { const f = (performance.now() - l).toFixed(2); throw C({ url: o, method: a, duration: f, status: "ERROR", stack: u }), d; } }; }; function A(n) { n.interceptors.request.use((e) => (e.metadata = { startTime: /* @__PURE__ */ new Date() }, e)), n.interceptors.response.use( (e) => { const o = /* @__PURE__ */ new Date() - e.config.metadata.startTime; return C({ method: e.config.method.toUpperCase(), url: e.config.url, duration: o, status: e.status }), e; }, (e) => { const o = e.config || {}, a = o.metadata ? /* @__PURE__ */ new Date() - o.metadata.startTime : 0; return C({ method: o.method ? o.method.toUpperCase() : "UNKNOWN", url: o.url || "unknown", duration: a, status: e.response ? e.response.status : "ERR" }), Promise.reject(e); } ); } const $ = () => { const [n, e] = y([]), [o, a] = y([]), [l, u] = y(!1), [m, d] = y(!1), [f, P] = y({ x: 0, y: 0 }), b = h(null), S = h(null), w = h({ x: window.innerWidth - 80, y: window.innerHeight - 80 }), g = h({ isDragging: !1, offsetX: 0, offsetY: 0 }), v = h(!1), T = (t, i) => { const s = b.current; if (!s) return; const p = Math.max(0, Math.min(t, window.innerWidth - s.offsetWidth)), c = Math.max(0, Math.min(i, window.innerHeight - s.offsetHeight)); s.style.left = `${p}px`, s.style.top = `${c}px`, s.style.right = "auto", s.style.bottom = "auto", w.current = { x: p, y: c }; }, H = () => { const t = S.current; if (!t) return; const { offsetWidth: i, offsetHeight: s } = t, { x: p, y: c } = w.current, L = p < window.innerWidth / 2, k = c < window.innerHeight / 2, I = L ? p + 10 : p - i - 10, N = k ? c + 10 : c - s - 10; P({ x: I, y: N }); }; return O(() => { l && H(); }, [l]), x(() => { const t = b.current; if (!t) return; const i = (c) => { g.current.isDragging = !0, v.current = !1, g.current.offsetX = c.clientX - t.offsetLeft, g.current.offsetY = c.clientY - t.offsetTop; }, s = (c) => { if (!g.current.isDragging) return; v.current = !0; const L = c.clientX - g.current.offsetX, k = c.clientY - g.current.offsetY; T(L, k); }, p = () => { g.current.isDragging = !1; }; return t.addEventListener("pointerdown", i), window.addEventListener("pointermove", s), window.addEventListener("pointerup", p), () => { t.removeEventListener("pointerdown", i), window.removeEventListener("pointermove", s), window.removeEventListener("pointerup", p); }; }, []), x(() => { const t = (i) => { i.ctrlKey && i.key === "`" && d((s) => !s); }; return window.addEventListener("keydown", t), () => window.removeEventListener("keydown", t); }, []), x(() => { const t = M(e), i = setInterval(() => { a(X()); }, 2e3); return () => { t(), clearInterval(i); }; }, []), m ? /* @__PURE__ */ r.createElement( "div", { ref: b, onClick: () => { v.current || u((t) => !t); }, style: { position: "fixed", zIndex: 1e4, left: w.current.x, top: w.current.y, width: 50, height: 50, borderRadius: "50%", background: "#000", color: "#fff", display: "none", // hide visually alignItems: "center", justifyContent: "center", fontSize: 24, cursor: "grab", userSelect: "none" }, title: "Toggle Debug Panel" }, "🐞" ) : /* @__PURE__ */ r.createElement(r.Fragment, null, /* @__PURE__ */ r.createElement( "div", { ref: b, onClick: () => { v.current || u((t) => !t); }, style: { position: "fixed", zIndex: 1e4, left: w.current.x, top: w.current.y, width: 50, height: 50, borderRadius: "50%", background: "#000", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 24, cursor: "grab", userSelect: "none" }, title: "Toggle Debug Panel" }, "🐞" ), l && /* @__PURE__ */ r.createElement( "div", { ref: S, className: "debug-panel", style: { position: "fixed", top: f.y, left: f.x, zIndex: 10001, width: 320, maxHeight: 400, overflowY: "auto", backgroundColor: "#111", color: "#fff", fontFamily: "monospace", borderRadius: 12, padding: 16, boxShadow: "0 8px 16px rgba(0,0,0,0.3)", transition: "opacity 0.3s ease" } }, /* @__PURE__ */ r.createElement("div", { style: { display: "flex", justifyContent: "space-between" } }, /* @__PURE__ */ r.createElement("strong", null, "Debug Info"), /* @__PURE__ */ r.createElement( "button", { onClick: () => u(!1), style: { background: "transparent", border: "none", color: "#fff", fontSize: "18px", cursor: "pointer" } }, "×" )), /* @__PURE__ */ r.createElement("div", { style: { marginTop: 10 } }, /* @__PURE__ */ r.createElement("strong", null, "Top Rendered Components"), /* @__PURE__ */ r.createElement("ul", { style: { paddingLeft: 15 } }, o.map(([t, i], s) => /* @__PURE__ */ r.createElement("li", { key: s }, t, ": ", i)))), /* @__PURE__ */ r.createElement("div", { style: { marginTop: 10 } }, /* @__PURE__ */ r.createElement("strong", null, "API Calls (", n.length, ")"), /* @__PURE__ */ r.createElement("ul", { style: { paddingLeft: 15 } }, n.slice(-5).reverse().map((t, i) => /* @__PURE__ */ r.createElement("li", { key: i }, /* @__PURE__ */ r.createElement("div", { style: { wordBreak: "break-word" } }, t.method, " ", t.url), /* @__PURE__ */ r.createElement("small", null, t.duration, "ms | ", t.status, " |", " ", t.time.toLocaleTimeString()))))) )); }; export { $ as DebugOverlay, X as getRenderStats, A as patchAxiosInstance, U as patchGlobalFetch, M as subscribeToApiLogs, F as useWhyRender }; //# sourceMappingURL=index.es.js.map