From 5d5b1669e82e60379f13bcfa9cc62abf429f43c4 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sat, 11 Jul 2026 16:01:05 -0500 Subject: [PATCH 1/2] feat(plugin): implement close method for plugin mode handling --- src/index.js | 9 +++++++++ test/pluginMode.test.js | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 test/pluginMode.test.js diff --git a/src/index.js b/src/index.js index 053d3b45e..f648ba9b9 100644 --- a/src/index.js +++ b/src/index.js @@ -596,10 +596,19 @@ function wdm(compiler, options = {}, isPlugin = false) { instance.invalidate = (callback = noop) => { middleware.ready(filledContext, callback); + // TODO for plugin usage (`isPlugin = true`) `watching` is `undefined` and this throws — + // invalidate the host's `compiler.watching` (each child's one for a `MultiCompiler`) instead filledContext.watching.invalidate(); }; instance.close = (callback = noop) => { + // For plugin usage the host (webpack-cli, webpack-dev-server, etc.) owns `compiler.watch()`, + // so there is no `watching` of our own to close (`compiler.close()` on the host handles it) + if (!filledContext.watching) { + callback(null); + return; + } + filledContext.watching.close(callback); }; diff --git a/test/pluginMode.test.js b/test/pluginMode.test.js new file mode 100644 index 000000000..e960a87e4 --- /dev/null +++ b/test/pluginMode.test.js @@ -0,0 +1,39 @@ +import middleware from "../src"; + +import webpackConfig from "./fixtures/webpack.config"; +import getCompiler from "./helpers/getCompiler"; + +jest.spyOn(globalThis.console, "log").mockImplementation(); + +// When used as a plugin (`isPlugin = true`) the host (webpack-cli, +// webpack-dev-server, etc.) owns `compiler.watch()`, so the middleware has no +// `watching` of its own +describe("plugin mode", () => { + describe("close method", () => { + it("should not throw and call the callback when the host is not watching", (done) => { + const compiler = getCompiler(webpackConfig); + const instance = middleware(compiler, {}, true); + + instance.close((error) => { + expect(error).toBeNull(); + + done(); + }); + }); + + it("should not close the watching owned by the host", (done) => { + const compiler = getCompiler(webpackConfig); + const watching = compiler.watch({}, () => {}); + const instance = middleware(compiler, {}, true); + + instance.waitUntilValid(() => { + instance.close((error) => { + expect(error).toBeNull(); + expect(watching.closed).toBe(false); + + watching.close(done); + }); + }); + }); + }); +}); From cd76955fb52cc6ca74c54d280e799079adcc3318 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sat, 11 Jul 2026 16:08:41 -0500 Subject: [PATCH 2/2] fix(plugin): resolve crash on close() in plugin mode --- .changeset/plugin-mode-close.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/plugin-mode-close.md diff --git a/.changeset/plugin-mode-close.md b/.changeset/plugin-mode-close.md new file mode 100644 index 000000000..5ad413429 --- /dev/null +++ b/.changeset/plugin-mode-close.md @@ -0,0 +1,5 @@ +--- +"webpack-dev-middleware": patch +--- + +Fixed a crash when calling `close()` in plugin mode (`isPlugin = true`). Since the host (webpack-cli, webpack-dev-server, etc.) owns `compiler.watch()`, the middleware has no `watching` of its own to close, so `close()` now just calls the callback instead of throwing.