diff --git a/client-src/index.js b/client-src/index.js
index 3a948884b5..7cd441bf4b 100644
--- a/client-src/index.js
+++ b/client-src/index.js
@@ -35,6 +35,30 @@ import createSocketURL from "./utils/createSocketURL.js";
* @property {string} [previousHash]
*/
+/**
+ * @param {boolean | { warnings?: boolean | string; errors?: boolean | string; runtimeErrors?: boolean | string; }} overlayOptions
+ */
+const decodeOverlayOptions = (overlayOptions) => {
+ if (typeof overlayOptions === "object") {
+ ["warnings", "errors", "runtimeErrors"].forEach((property) => {
+ if (typeof overlayOptions[property] === "string") {
+ const overlayFilterFunctionString = decodeURIComponent(
+ overlayOptions[property]
+ );
+
+ // eslint-disable-next-line no-new-func
+ const overlayFilterFunction = new Function(
+ "message",
+ `var callback = ${overlayFilterFunctionString}
+ return callback(message)`
+ );
+
+ overlayOptions[property] = overlayFilterFunction;
+ }
+ });
+ }
+};
+
/**
* @type {Status}
*/
@@ -92,22 +116,7 @@ if (parsedResourceQuery.overlay) {
...options.overlay,
};
- ["errors", "warnings", "runtimeErrors"].forEach((property) => {
- if (typeof options.overlay[property] === "string") {
- const overlayFilterFunctionString = decodeURIComponent(
- options.overlay[property]
- );
-
- // eslint-disable-next-line no-new-func
- const overlayFilterFunction = new Function(
- "message",
- `var callback = ${overlayFilterFunctionString}
- return callback(message)`
- );
-
- options.overlay[property] = overlayFilterFunction;
- }
- });
+ decodeOverlayOptions(options.overlay);
}
enabledFeatures.Overlay = true;
}
@@ -198,6 +207,7 @@ const onSocketMessage = {
}
options.overlay = value;
+ decodeOverlayOptions(options.overlay);
},
/**
* @param {number} value
diff --git a/lib/Server.js b/lib/Server.js
index 03deff124e..2d67d2b72a 100644
--- a/lib/Server.js
+++ b/lib/Server.js
@@ -240,6 +240,16 @@ const memoize = (fn) => {
const getExpress = memoize(() => require("express"));
+/**
+ *
+ * @param {OverlayMessageOptions} [setting]
+ * @returns
+ */
+const encodeOverlaySettings = (setting) =>
+ typeof setting === "function"
+ ? encodeURIComponent(setting.toString())
+ : setting;
+
class Server {
/**
* @param {Configuration | Compiler | MultiCompiler} options
@@ -658,16 +668,6 @@ class Server {
}
if (typeof client.overlay !== "undefined") {
- /**
- *
- * @param {OverlayMessageOptions} [setting]
- * @returns
- */
- const encodeOverlaySettings = (setting) =>
- typeof setting === "function"
- ? encodeURIComponent(setting.toString())
- : setting;
-
const overlayString =
typeof client.overlay === "boolean"
? String(client.overlay)
@@ -2647,11 +2647,26 @@ class Server {
/** @type {ClientConfiguration} */
(this.options.client).overlay
) {
+ const overlayConfig = /** @type {ClientConfiguration} */ (
+ this.options.client
+ ).overlay;
+
this.sendMessage(
[client],
"overlay",
- /** @type {ClientConfiguration} */
- (this.options.client).overlay
+ typeof overlayConfig === "object"
+ ? {
+ errors:
+ overlayConfig.errors &&
+ encodeOverlaySettings(overlayConfig.errors),
+ warnings:
+ overlayConfig.warnings &&
+ encodeOverlaySettings(overlayConfig.warnings),
+ runtimeErrors:
+ overlayConfig.runtimeErrors &&
+ encodeOverlaySettings(overlayConfig.runtimeErrors),
+ }
+ : overlayConfig
);
}
diff --git a/test/e2e/__snapshots__/overlay.test.js.snap.webpack4 b/test/e2e/__snapshots__/overlay.test.js.snap.webpack4
index eca0d83aba..44a1317cf9 100644
--- a/test/e2e/__snapshots__/overlay.test.js.snap.webpack4
+++ b/test/e2e/__snapshots__/overlay.test.js.snap.webpack4
@@ -2221,3 +2221,213 @@ exports[`overlay should show error for uncaught runtime error: overlay html 1`]
+
"
`;
+
+exports[`overlay should show warning when it is not filtered: overlay html 1`] = `
+"
+
+
+ Compiled with problems:
+
+
+
+
+
+ WARNING
+
+
+ Unfiltered warning
+
+
+
+
+
+"
+`;
+
+exports[`overlay should show warning when it is not filtered: page html 1`] = `
+"
+
webpack-dev-server is running...
+
+
+
+
+"
+`;
diff --git a/test/e2e/overlay.test.js b/test/e2e/overlay.test.js
index 11f9d3bd4a..6ea8cb60c5 100644
--- a/test/e2e/overlay.test.js
+++ b/test/e2e/overlay.test.js
@@ -596,6 +596,90 @@ describe("overlay", () => {
await server.stop();
});
+ it("should not show warning when it is filtered", async () => {
+ const compiler = webpack(config);
+
+ new WarningPlugin("My special warning").apply(compiler);
+
+ const server = new Server(
+ {
+ port,
+ client: {
+ overlay: {
+ warnings: (error) => {
+ // error is string in webpack 4
+ const message = typeof error === "string" ? error : error.message;
+ return message !== "My special warning";
+ },
+ },
+ },
+ },
+ compiler
+ );
+
+ await server.start();
+
+ const { page, browser } = await runBrowser();
+
+ await page.goto(`http://localhost:${port}/`, {
+ waitUntil: "networkidle0",
+ });
+
+ const overlayHandle = await page.$("#webpack-dev-server-client-overlay");
+
+ expect(overlayHandle).toBe(null);
+
+ await browser.close();
+ await server.stop();
+ });
+
+ it("should show warning when it is not filtered", async () => {
+ const compiler = webpack(config);
+
+ new WarningPlugin("Unfiltered warning").apply(compiler);
+
+ const server = new Server(
+ {
+ port,
+ client: {
+ overlay: {
+ warnings: () => true,
+ },
+ },
+ },
+ compiler
+ );
+
+ await server.start();
+
+ const { page, browser } = await runBrowser();
+
+ try {
+ await page.goto(`http://localhost:${port}/`, {
+ waitUntil: "networkidle0",
+ });
+
+ const pageHtml = await page.evaluate(() => document.body.outerHTML);
+ const overlayHandle = await page.$("#webpack-dev-server-client-overlay");
+ const overlayFrame = await overlayHandle.contentFrame();
+ const overlayHtml = await overlayFrame.evaluate(
+ () => document.body.outerHTML
+ );
+
+ expect(prettier.format(pageHtml, { parser: "html" })).toMatchSnapshot(
+ "page html"
+ );
+ expect(prettier.format(overlayHtml, { parser: "html" })).toMatchSnapshot(
+ "overlay html"
+ );
+ } catch (error) {
+ console.error(error);
+ }
+
+ await browser.close();
+ await server.stop();
+ });
+
it('should show a warning when "client.overlay" is "true"', async () => {
const compiler = webpack(config);
@@ -785,6 +869,95 @@ describe("overlay", () => {
await server.stop();
});
+ it("should not show error when it is filtered", async () => {
+ const compiler = webpack(config);
+
+ new ErrorPlugin("My special error").apply(compiler);
+
+ const server = new Server(
+ {
+ port,
+ client: {
+ overlay: {
+ errors: (error) => {
+ // error is string in webpack 4
+ const message = typeof error === "string" ? error : error.message;
+
+ return message !== "My special error";
+ },
+ },
+ },
+ },
+ compiler
+ );
+
+ await server.start();
+
+ const { page, browser } = await runBrowser();
+
+ try {
+ await page.goto(`http://localhost:${port}/`, {
+ waitUntil: "networkidle0",
+ });
+
+ const overlayHandle = await page.$("#webpack-dev-server-client-overlay");
+
+ expect(overlayHandle).toBe(null);
+ } catch (error) {
+ console.error(error);
+ }
+
+ await browser.close();
+ await server.stop();
+ });
+
+ it("should show error when it is not filtered", async () => {
+ const compiler = webpack(config);
+
+ new ErrorPlugin("Unfiltered error").apply(compiler);
+
+ const server = new Server(
+ {
+ port,
+ client: {
+ overlay: {
+ errors: () => true,
+ },
+ },
+ },
+ compiler
+ );
+
+ await server.start();
+
+ const { page, browser } = await runBrowser();
+
+ try {
+ await page.goto(`http://localhost:${port}/`, {
+ waitUntil: "networkidle0",
+ });
+
+ const pageHtml = await page.evaluate(() => document.body.outerHTML);
+ const overlayHandle = await page.$("#webpack-dev-server-client-overlay");
+ const overlayFrame = await overlayHandle.contentFrame();
+ const overlayHtml = await overlayFrame.evaluate(
+ () => document.body.outerHTML
+ );
+
+ expect(prettier.format(pageHtml, { parser: "html" })).toMatchSnapshot(
+ "page html"
+ );
+ expect(prettier.format(overlayHtml, { parser: "html" })).toMatchSnapshot(
+ "overlay html"
+ );
+ } catch (error) {
+ console.error(error);
+ }
+
+ await browser.close();
+ await server.stop();
+ });
+
it('should show an error when "client.overlay" is "true"', async () => {
const compiler = webpack(config);
@@ -1184,7 +1357,7 @@ describe("overlay", () => {
await server.stop();
});
- it("show not show filtered runtime error", async () => {
+ it("should not show filtered runtime error", async () => {
const compiler = webpack(config);
const server = new Server(
diff --git a/types/lib/Server.d.ts b/types/lib/Server.d.ts
index 7361906c51..ab8c6e3d08 100644
--- a/types/lib/Server.d.ts
+++ b/types/lib/Server.d.ts
@@ -665,9 +665,16 @@ declare class Server {
}
| {
description: string;
+ /**
+ * @private
+ * @type {RequestHandler[]}
+ */
multiple: boolean;
path: string;
type: string;
+ /**
+ * @type {Socket[]}
+ */
}
)[];
description: string;
@@ -774,6 +781,9 @@ declare class Server {
simpleType: string;
multiple: boolean;
};
+ /**
+ * @type {string | undefined}
+ */
"https-ca": {
configs: {
type: string;
@@ -808,10 +818,6 @@ declare class Server {
multiple: boolean;
};
"https-cacert-reset": {
- /**
- * @private
- * @param {Compiler} compiler
- */
configs: {
description: string;
multiple: boolean;
@@ -826,7 +832,7 @@ declare class Server {
configs: {
type: string;
multiple: boolean;
- description: string;
+ /** @type {ClientConfiguration} */ description: string;
path: string;
}[];
description: string;
@@ -886,7 +892,7 @@ declare class Server {
}[];
description: string;
multiple: boolean;
- simpleType: string;
+ /** @type {string} */ simpleType: string;
};
"https-passphrase": {
configs: {
@@ -897,7 +903,7 @@ declare class Server {
}[];
description: string;
simpleType: string;
- /** @type {ClientConfiguration} */ multiple: boolean;
+ multiple: boolean;
};
"https-pfx": {
configs: {
@@ -983,12 +989,12 @@ declare class Server {
type: string;
multiple: boolean;
description: string;
+ /** @type {any} */
path: string;
}
| {
type: string;
multiple: boolean;
- /** @type {any} */
description: string;
negatedDescription: string;
path: string;
@@ -1018,8 +1024,9 @@ declare class Server {
}[];
description: string;
simpleType: string;
- multiple: boolean;
+ multiple: boolean /** @type {MultiCompiler} */;
};
+ /** @type {MultiCompiler} */
"open-app-name-reset": {
configs: {
type: string;
@@ -1091,6 +1098,10 @@ declare class Server {
path: string;
type: string;
}[];
+ /**
+ * @param {string | Static | undefined} [optionsForStatic]
+ * @returns {NormalizedStatic}
+ */
description: string;
multiple: boolean;
simpleType: string;
@@ -1261,7 +1272,7 @@ declare class Server {
}
| {
type: string;
- /** @type {ServerConfiguration} */ multiple: boolean;
+ multiple: boolean;
description: string;
negatedDescription: string;
path: string;
@@ -1278,15 +1289,15 @@ declare class Server {
description: string;
path: string;
}[];
- description: string;
+ /** @type {ServerOptions} */ description: string;
simpleType: string;
- multiple: boolean /** @type {ServerOptions} */;
+ multiple: boolean;
};
"static-public-path": {
configs: {
type: string;
multiple: boolean;
- /** @type {ServerOptions} */ description: string;
+ description: string;
path: string;
}[];
description: string;
@@ -2126,10 +2137,6 @@ declare class Server {
}
| {
type: string;
- /**
- * @private
- * @type {{ name: string | symbol, listener: (...args: any[]) => void}[] }}
- */
additionalProperties: boolean;
properties: {
passphrase: {
@@ -2143,6 +2150,10 @@ declare class Server {
negatedDescription: string;
};
};
+ /**
+ * @private
+ * @type {string | undefined}
+ */
ca: {
anyOf: (
| {
@@ -2406,6 +2417,7 @@ declare class Server {
| {
type: string;
description: string;
+ /** @type {{ type: WebSocketServerConfiguration["type"], options: NonNullable
}} */
link: string;
cli?: undefined;
}
@@ -2440,7 +2452,7 @@ declare class Server {
}
| {
enum: string[];
- type?: undefined;
+ /** @type {string} */ type?: undefined;
cli?: undefined;
}
)[];
@@ -2469,7 +2481,7 @@ declare class Server {
cli: {
negatedDescription: string;
};
- link: string /** @type {number | string} */;
+ link: string;
};
MagicHTML: {
type: string;
@@ -2606,12 +2618,6 @@ declare class Server {
| {
type: string;
minLength: number;
- /**
- * prependEntry Method for webpack 4
- * @param {any} originalEntry
- * @param {any} newAdditionalEntries
- * @returns {any}
- */
minimum?: undefined;
maximum?: undefined;
enum?: undefined;
@@ -2688,7 +2694,7 @@ declare class Server {
$ref: string;
};
};
- /** @type {MultiCompiler} */ additionalProperties: boolean;
+ additionalProperties: boolean;
};
ServerOptions: {
type: string;
@@ -2696,7 +2702,7 @@ declare class Server {
properties: {
passphrase: {
type: string;
- /** @type {MultiCompiler} */ description: string;
+ description: string;
};
requestCert: {
type: string;
@@ -2744,10 +2750,6 @@ declare class Server {
anyOf: (
| {
type: string;
- /**
- * @private
- * @returns {Promise}
- */
instanceof?: undefined;
}
| {
@@ -2769,10 +2771,6 @@ declare class Server {
items?: undefined;
}
)[];
- /**
- * @param {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} watchOptions
- * @returns {WatchOptions}
- */
description: string;
};
cert: {
@@ -3126,6 +3124,7 @@ declare class Server {
};
WebSocketServerObject: {
type: string;
+ /** @type {ServerOptions} */
properties: {
type: {
anyOf: {
@@ -3135,12 +3134,13 @@ declare class Server {
options: {
type: string;
additionalProperties: boolean;
+ /** @type {ServerOptions} */
cli: {
exclude: boolean;
};
};
};
- /** @type {ServerOptions} */ additionalProperties: boolean;
+ additionalProperties: boolean;
};
WebSocketServerString: {
type: string;
@@ -3195,8 +3195,9 @@ declare class Server {
$ref: string;
};
onBeforeSetupMiddleware: {
- $ref: string;
+ $ref: string /** @type {any} */;
};
+ /** @type {any} */
onListening: {
$ref: string;
};