mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-15 00:08:15 +00:00
fix(boot): ignore ResizeObserver loop notifications (#2405)
Fixes #2397 The startup guard in public/boot.js treated every window error with a message as fatal, including the benign "ResizeObserver loop completed with undelivered notifications" (and "loop limit exceeded") that a layout during startup can raise without an error object. These are now ignored; real errors, rejections, script load failures and the 30 s timeout still show the failure page.
This commit is contained in:
@@ -90,6 +90,13 @@
|
||||
if (target?.tagName === "SCRIPT" || (target?.tagName === "LINK" && target.rel === "modulepreload")) {
|
||||
show(`Could not load startup script: ${target.src || target.href}`);
|
||||
} else if (event.error || event.message) {
|
||||
// ResizeObserver defers undelivered notifications to the next frame; startup can continue.
|
||||
if (
|
||||
!event.error &&
|
||||
(event.message === "ResizeObserver loop completed with undelivered notifications." ||
|
||||
event.message === "ResizeObserver loop limit exceeded")
|
||||
)
|
||||
return;
|
||||
show(event.error || `${event.message}\n${event.filename || ""}:${event.lineno || 0}:${event.colno || 0}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,6 +24,50 @@ it("surfaces module evaluation errors before React is available", () => {
|
||||
expect(document.querySelector("textarea")?.value).toContain(navigator.userAgent);
|
||||
});
|
||||
|
||||
const resizeObserverMessages = [
|
||||
"ResizeObserver loop completed with undelivered notifications.",
|
||||
"ResizeObserver loop limit exceeded",
|
||||
];
|
||||
|
||||
it.each(resizeObserverMessages)("keeps waiting for boot-ready after %s", (message) => {
|
||||
window.dispatchEvent(new ErrorEvent("error", { message, filename: "tauri://localhost" }));
|
||||
expect(document.getElementById("splash")).not.toBeNull();
|
||||
expect(document.getElementById("boot-error")).toBeNull();
|
||||
expect(document.documentElement.dataset.boot).toBeUndefined();
|
||||
window.dispatchEvent(new Event("openidea:boot-ready"));
|
||||
vi.advanceTimersByTime(30_000);
|
||||
expect(document.getElementById("boot-error")).toBeNull();
|
||||
});
|
||||
|
||||
it.each(resizeObserverMessages)("still reports a real failure after %s", (message) => {
|
||||
window.dispatchEvent(new ErrorEvent("error", { message }));
|
||||
window.dispatchEvent(new ErrorEvent("error", { error: new Error("startup failed") }));
|
||||
expect(document.getElementById("splash")).toBeNull();
|
||||
expect(document.querySelector("textarea")?.value).toContain("startup failed");
|
||||
expect(document.querySelector("textarea")?.value).not.toContain(message);
|
||||
});
|
||||
|
||||
it.each(resizeObserverMessages)("still times out an unresolved startup after %s", (message) => {
|
||||
vi.advanceTimersByTime(15_000);
|
||||
window.dispatchEvent(new ErrorEvent("error", { message }));
|
||||
vi.advanceTimersByTime(15_000);
|
||||
expect(document.querySelector("textarea")?.value).toContain("Startup did not finish within 30 seconds.");
|
||||
});
|
||||
|
||||
it.each(resizeObserverMessages)("keeps actual errors with the same message fatal: %s", (message) => {
|
||||
window.dispatchEvent(new ErrorEvent("error", { message, error: new Error(message) }));
|
||||
expect(document.getElementById("splash")).toBeNull();
|
||||
expect(document.querySelector("textarea")?.value).toContain(message);
|
||||
});
|
||||
|
||||
it.each(resizeObserverMessages)("keeps rejections with the same message fatal: %s", (message) => {
|
||||
const event = new Event("unhandledrejection");
|
||||
Object.defineProperty(event, "reason", { value: message });
|
||||
window.dispatchEvent(event);
|
||||
expect(document.getElementById("splash")).toBeNull();
|
||||
expect(document.querySelector("textarea")?.value).toContain(message);
|
||||
});
|
||||
|
||||
it("handles startup rejections and preserves the first failure", () => {
|
||||
const event = new Event("unhandledrejection");
|
||||
Object.defineProperty(event, "reason", { value: { message: "startup rejected" } });
|
||||
@@ -46,6 +90,20 @@ it("handles script load failures but ignores image failures", () => {
|
||||
expect(document.querySelector("textarea")?.value).toContain("/assets/entry.js");
|
||||
});
|
||||
|
||||
it("handles modulepreload load failures", () => {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "modulepreload";
|
||||
link.href = "/assets/dependency.js";
|
||||
document.head.append(link);
|
||||
try {
|
||||
link.dispatchEvent(new Event("error"));
|
||||
expect(document.getElementById("splash")).toBeNull();
|
||||
expect(document.querySelector("textarea")?.value).toContain("/assets/dependency.js");
|
||||
} finally {
|
||||
link.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it("surfaces initial React render failures through the boot error event", () => {
|
||||
window.dispatchEvent(new CustomEvent("openidea:boot-error", { detail: new Error("render failed") }));
|
||||
expect(document.querySelector("textarea")?.value).toContain("render failed");
|
||||
|
||||
Reference in New Issue
Block a user