| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /** |
| * Counts React commits, rendered fibers, and the `setState` calls that caused |
| * them, from inside the renderer (#4109). |
| * |
| * Injected with `Page.addScriptToEvaluateOnNewDocument` before the app loads, |
| * because both halves have to be in place first: |
| * |
| * 1. `__REACT_DEVTOOLS_GLOBAL_HOOK__` must exist before `react-dom` looks for |
| * it, or no commit is ever reported. This is a minimal stand-in for the |
| * DevTools hook — enough of the shape that react-dom injects into it. |
| * |
| * 2. `Function.prototype.bind` is wrapped to catch React creating a state |
| * dispatcher. React binds `dispatchSetState` as `(null, fiber, queue)`, |
| * and the queue is the only object in the runtime carrying |
| * `lastRenderedReducer`, so that triple identifies it with no version |
| * coupling to react-dom's internals. |
| * |
| * A fiber counts as rendered when it carries `Placement` (`flags & 1`) and its |
| * alternate was last seen in the previous commit. That is identity-insensitive: |
| * it reports what React actually re-rendered, not what a `memo` comparator was |
| * asked about. |
| * |
| * `arm` gates recording so a measurement covers one interaction rather than the |
| * app's whole life. Set `__MAKA_PROBE__.arm = false` before profiling with the |
| * sampler, or the probe's own walk lands in the profile. |
| */ |
| (() => { |
| if (globalThis.__MAKA_PROBE__) return 'already'; |
| const probe = { |
| commits: [], |
| dispatches: [], |
| arm: false, |
| roots: new Set(), |
| rootIdx: new WeakMap(), |
| qid: 0, |
| qlabel: new Map(), |
| }; |
| globalThis.__MAKA_PROBE__ = probe; |
| |
| const originalBind = Function.prototype.bind; |
| Function.prototype.bind = function bind(...args) { |
| const bound = originalBind.apply(this, args); |
| try { |
| const queue = args[2]; |
| if ( |
| args.length === 3 && |
| args[0] === null && |
| queue && |
| typeof queue === 'object' && |
| 'lastRenderedReducer' in queue && |
| !queue.__qid |
| ) { |
| queue.__qid = ++probe.qid; |
| const qid = queue.__qid; |
| return function dispatchWithRecord(action) { |
| if (probe.arm && probe.dispatches.length < 500) { |
| probe.dispatches.push({ |
| t: performance.now(), |
| qid, |
| prev: brief(queue.lastRenderedState), |
| action: brief(action), |
| st: (new Error().stack || '') |
| .split('\n') |
| .slice(2, 8) |
| .map((line) => line.trim().slice(0, 130)), |
| }); |
| } |
| return bound.apply(this, arguments); |
| }; |
| } |
| } catch { |
| // A bind we cannot inspect is a bind we do not care about. |
| } |
| return bound; |
| }; |
| |
| function brief(value) { |
| try { |
| if (value == null) return String(value); |
| if (typeof value === 'function') return 'fn'; |
| if (typeof value !== 'object') return String(value).slice(0, 40); |
| if (Array.isArray(value)) return `Arr${value.length}`; |
| return `{${Object.keys(value).slice(0, 6)}}`; |
| } catch { |
| return '?'; |
| } |
| } |
| |
| const nameOf = (fiber) => { |
| const type = fiber.type ?? fiber.elementType; |
| if (typeof type === 'string') return type; |
| if (typeof type === 'function') return type.displayName || type.name || 'anon'; |
| if (type && typeof type === 'object') { |
| const inner = type.type ?? type.render; |
| return ( |
| type.displayName || |
| (typeof inner === 'function' ? inner.displayName || inner.name : null) || |
| 'obj' |
| ); |
| } |
| return `tag${fiber.tag}`; |
| }; |
| |
| const hook = { |
| renderers: new Map(), |
| supportsFiber: true, |
| _nextId: 1, |
| inject(renderer) { |
| const id = hook._nextId++; |
| hook.renderers.set(id, renderer); |
| return id; |
| }, |
| checkDCE() {}, |
| onScheduleFiberRoot() {}, |
| onCommitFiberUnmount() {}, |
| onPostCommitFiberRoot() {}, |
| setStrictMode() {}, |
| getFiberRoots() { |
| return probe.roots; |
| }, |
| on() {}, |
| off() {}, |
| sub() { |
| return () => {}; |
| }, |
| emit() {}, |
| onCommitFiberRoot(_id, root) { |
| probe.roots.add(root); |
| const idx = (probe.rootIdx.get(root) || 0) + 1; |
| probe.rootIdx.set(root, idx); |
| const key = '__pc'; |
| let total = 0; |
| let visited = 0; |
| const renderRoots = []; |
| const stack = [[root.current, 0, false]]; |
| while (stack.length) { |
| const [fiber, depth, hasRenderedAncestor] = stack.pop(); |
| if (!fiber || visited++ > 90000) break; |
| const alternate = fiber.alternate; |
| const rendered = fiber.flags & 1 && alternate && alternate[key] === idx - 1; |
| if (rendered) total++; |
| let ancestor = hasRenderedAncestor; |
| if (rendered && !hasRenderedAncestor && probe.arm) { |
| ancestor = true; |
| renderRoots.push({ d: depth, name: nameOf(fiber) }); |
| } |
| let state = fiber.memoizedState; |
| let i = 0; |
| while (state && i < 1200) { |
| if (state.queue?.__qid && !probe.qlabel.has(state.queue.__qid)) { |
| probe.qlabel.set(state.queue.__qid, `${nameOf(fiber)}@d${depth}#h${i}`); |
| } |
| state = state.next; |
| i++; |
| } |
| fiber[key] = idx; |
| if (fiber.child) stack.push([fiber.child, depth + 1, ancestor]); |
| if (fiber.sibling) stack.push([fiber.sibling, depth, hasRenderedAncestor]); |
| } |
| if (probe.arm && probe.commits.length < 300) { |
| renderRoots.sort((a, b) => a.d - b.d); |
| probe.commits.push({ t: performance.now(), idx, total, rr: renderRoots.slice(0, 3) }); |
| } |
| }, |
| }; |
| Object.defineProperty(globalThis, '__REACT_DEVTOOLS_GLOBAL_HOOK__', { |
| value: hook, |
| writable: false, |
| configurable: true, |
| }); |
| return 'installed'; |
| })(); |