diff --git a/client-src/index.js b/client-src/index.js index 60527ef029..3aa955bc50 100644 --- a/client-src/index.js +++ b/client-src/index.js @@ -45,6 +45,7 @@ import sendMessage from "./utils/sendMessage.js"; * @property {boolean} isUnloading true when unloaded, otherwise false * @property {string} currentHash current hash * @property {string=} previousHash previous hash + * @property {boolean} hasRuntimeError true when a runtime error occurred */ /** @@ -84,8 +85,17 @@ const decodeOverlayOptions = (overlayOptions) => { const status = { isUnloading: false, currentHash: __webpack_hash__, + hasRuntimeError: false, }; +if (typeof window !== "undefined" && window.addEventListener) { + window.addEventListener("error", () => { + status.hasRuntimeError = true; + }); + window.addEventListener("unhandledrejection", () => { + status.hasRuntimeError = true; + }); +} /** * @returns {string} current script source */ @@ -403,8 +413,7 @@ const onSocketMessage = { invalid() { log.info("App updated. Recompiling..."); - // Fixes #1042. overlay doesn't clear if errors are fixed but warnings remain. - if (options.overlay) { + if (options.overlay && !status.hasRuntimeError) { overlay.send({ type: "DISMISS" }); } @@ -473,7 +482,7 @@ const onSocketMessage = { "still-ok": function stillOk() { log.info("Nothing changed."); - if (options.overlay) { + if (options.overlay && !status.hasRuntimeError) { overlay.send({ type: "DISMISS" }); } @@ -482,6 +491,8 @@ const onSocketMessage = { ok() { sendMessage("Ok"); + status.hasRuntimeError = false; + if (options.overlay) { overlay.send({ type: "DISMISS" }); } diff --git a/test/e2e/overlay.test.js b/test/e2e/overlay.test.js index be3c059233..114c413aaa 100644 --- a/test/e2e/overlay.test.js +++ b/test/e2e/overlay.test.js @@ -1976,4 +1976,40 @@ describe("overlay", () => { await server.stop(); } }); + + it("should keep overlay visible for runtime error on initial load", async () => { + const compiler = webpack(config); + + const server = new Server( + { + port, + }, + compiler, + ); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0", + }); + + await page.addScriptTag({ + content: ` + throw new Error("Initial runtime error"); + `, + }); + + await delay(1000); + + const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); + + expect(overlayHandle).not.toBeNull(); + } finally { + await browser.close(); + await server.stop(); + } + }); }); diff --git a/test/fixtures/overlay-runtime-error.js b/test/fixtures/overlay-runtime-error.js new file mode 100644 index 0000000000..e2891e4a51 --- /dev/null +++ b/test/fixtures/overlay-runtime-error.js @@ -0,0 +1 @@ +throw new Error("Initial runtime error");