Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
192 lines
6.4 KiB
JavaScript
192 lines
6.4 KiB
JavaScript
/*
|
|
* 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';
|
|
})();
|