chore: add pre-blazor crash diagnostics
This commit is contained in:
@@ -25,11 +25,16 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<Routes @rendermode="@(new InteractiveServerRenderMode(prerender: false))"/>
|
||||
<div id="rr-interactive-host" data-request-path="@RequestPath">
|
||||
<Routes @rendermode="@(new InteractiveServerRenderMode(prerender: false))"/>
|
||||
</div>
|
||||
}
|
||||
<script src="js/rpgroller-api.js"></script>
|
||||
@if (UseInteractiveApp)
|
||||
{
|
||||
<script>
|
||||
window.rpgRollerApi.bootstrapPreBlazorDiagnostics("@RequestPath");
|
||||
</script>
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
}
|
||||
</body>
|
||||
@@ -55,6 +60,8 @@ else
|
||||
|
||||
private bool AuthStatusIsError => string.Equals(ReadAuthQueryValue("kind"), "error", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private string RequestPath => HttpContext?.Request.Path.Value ?? "/";
|
||||
|
||||
private string BaseHref
|
||||
{
|
||||
get
|
||||
|
||||
@@ -13,6 +13,7 @@ window.rpgRollerApi = (() => {
|
||||
observer: null,
|
||||
route: null,
|
||||
globalHandlersInstalled: false,
|
||||
domOperationDiagnosticsInstalled: false,
|
||||
mutationBatchCount: 0
|
||||
};
|
||||
|
||||
@@ -24,6 +25,14 @@ window.rpgRollerApi = (() => {
|
||||
console.warn(debugPrefix, new Date().toISOString(), ...args);
|
||||
}
|
||||
|
||||
function summarizeChildren(element) {
|
||||
if (!element || !element.childNodes) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Array.from(element.childNodes).slice(0, 20).map(summarizeNode);
|
||||
}
|
||||
|
||||
function summarizeNode(node) {
|
||||
if (!node) {
|
||||
return "<null>";
|
||||
@@ -117,6 +126,53 @@ window.rpgRollerApi = (() => {
|
||||
});
|
||||
}
|
||||
|
||||
function installDomOperationDiagnostics() {
|
||||
if (workspaceDiagnostics.domOperationDiagnosticsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
workspaceDiagnostics.domOperationDiagnosticsInstalled = true;
|
||||
const originalInsertBefore = Node.prototype.insertBefore;
|
||||
const originalAppendChild = Node.prototype.appendChild;
|
||||
const originalRemoveChild = Node.prototype.removeChild;
|
||||
const originalReplaceChild = Node.prototype.replaceChild;
|
||||
|
||||
Node.prototype.insertBefore = function (newNode, referenceNode) {
|
||||
debug("dom insertBefore", {
|
||||
parent: summarizeNode(this),
|
||||
newNode: summarizeNode(newNode),
|
||||
referenceNode: summarizeNode(referenceNode),
|
||||
referenceParent: referenceNode ? summarizeNode(referenceNode.parentNode) : null
|
||||
});
|
||||
return originalInsertBefore.call(this, newNode, referenceNode);
|
||||
};
|
||||
|
||||
Node.prototype.appendChild = function (child) {
|
||||
debug("dom appendChild", {
|
||||
parent: summarizeNode(this),
|
||||
child: summarizeNode(child)
|
||||
});
|
||||
return originalAppendChild.call(this, child);
|
||||
};
|
||||
|
||||
Node.prototype.removeChild = function (child) {
|
||||
debug("dom removeChild", {
|
||||
parent: summarizeNode(this),
|
||||
child: summarizeNode(child)
|
||||
});
|
||||
return originalRemoveChild.call(this, child);
|
||||
};
|
||||
|
||||
Node.prototype.replaceChild = function (newChild, oldChild) {
|
||||
debug("dom replaceChild", {
|
||||
parent: summarizeNode(this),
|
||||
newChild: summarizeNode(newChild),
|
||||
oldChild: summarizeNode(oldChild)
|
||||
});
|
||||
return originalReplaceChild.call(this, newChild, oldChild);
|
||||
};
|
||||
}
|
||||
|
||||
function summarizeMutation(mutation) {
|
||||
return {
|
||||
type: mutation.type,
|
||||
@@ -181,6 +237,79 @@ window.rpgRollerApi = (() => {
|
||||
logWorkspaceSnapshot(`phase:${label}`);
|
||||
}
|
||||
|
||||
function bootstrapPreBlazorDiagnostics(requestPath) {
|
||||
installGlobalDiagnostics();
|
||||
installDomOperationDiagnostics();
|
||||
|
||||
const host = document.getElementById("rr-interactive-host");
|
||||
workspaceDiagnostics.route = requestPath;
|
||||
debug("bootstrapPreBlazorDiagnostics", {
|
||||
requestPath,
|
||||
readyState: document.readyState,
|
||||
bodyChildren: summarizeChildren(document.body),
|
||||
host: summarizeNode(host),
|
||||
hostChildren: summarizeChildren(host)
|
||||
});
|
||||
|
||||
if (!host) {
|
||||
warn("bootstrapPreBlazorDiagnostics missing host", { requestPath });
|
||||
return;
|
||||
}
|
||||
|
||||
const preconnectObserver = new MutationObserver((mutations) => {
|
||||
debug("preblazor host mutations", {
|
||||
requestPath,
|
||||
mutations: mutations.slice(0, 20).map(summarizeMutation),
|
||||
bodyChildren: summarizeChildren(document.body),
|
||||
hostChildren: summarizeChildren(host)
|
||||
});
|
||||
});
|
||||
|
||||
preconnectObserver.observe(host, {
|
||||
subtree: true,
|
||||
childList: true,
|
||||
attributes: true,
|
||||
characterData: false
|
||||
});
|
||||
|
||||
const bodyObserver = new MutationObserver((mutations) => {
|
||||
debug("preblazor body mutations", {
|
||||
requestPath,
|
||||
mutations: mutations.slice(0, 20).map(summarizeMutation),
|
||||
bodyChildren: summarizeChildren(document.body),
|
||||
hostChildren: summarizeChildren(host)
|
||||
});
|
||||
});
|
||||
|
||||
bodyObserver.observe(document.body, {
|
||||
subtree: false,
|
||||
childList: true,
|
||||
attributes: false
|
||||
});
|
||||
|
||||
queueMicrotask(() => {
|
||||
debug("preblazor microtask snapshot", {
|
||||
requestPath,
|
||||
bodyChildren: summarizeChildren(document.body),
|
||||
hostChildren: summarizeChildren(host)
|
||||
});
|
||||
});
|
||||
requestAnimationFrame(() => {
|
||||
debug("preblazor raf snapshot", {
|
||||
requestPath,
|
||||
bodyChildren: summarizeChildren(document.body),
|
||||
hostChildren: summarizeChildren(host)
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
debug("preblazor timeout50 snapshot", {
|
||||
requestPath,
|
||||
bodyChildren: summarizeChildren(document.body),
|
||||
hostChildren: summarizeChildren(host)
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function toAppUrl(url) {
|
||||
if (!url || typeof url !== "string") {
|
||||
return url;
|
||||
@@ -588,6 +717,7 @@ window.rpgRollerApi = (() => {
|
||||
scrollElementToBottom,
|
||||
clearInputValue,
|
||||
installWorkspaceDiagnostics,
|
||||
markWorkspacePhase
|
||||
markWorkspacePhase,
|
||||
bootstrapPreBlazorDiagnostics
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user