From ac02012a2b8fa7d3213158a25f91acde6d2371ff Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Sat, 7 Feb 2026 20:09:36 -0800 Subject: [PATCH 1/2] fix: strip query strings before matching exclude patterns Vite appends cache-busting query strings (e.g. ?t=1707350000) to module URLs during HMR. The exclude patterns use $ anchors that expect the URL to end with the file extension (e.g. /.*\.tsx?$/), which fails to match URLs with query parameters. This causes HMR module requests to leak through to the app server, which returns 404 with text/plain MIME type. The browser rejects the module and the page goes blank. Fix by also testing exclude patterns against the URL path (without query string), so /frontend/App.tsx?t=123 correctly matches /.*\.tsx?$/ via the path portion /frontend/App.tsx. --- src/dev-server.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dev-server.ts b/src/dev-server.ts index 7e5ef8c..d35dc68 100644 --- a/src/dev-server.ts +++ b/src/dev-server.ts @@ -63,15 +63,16 @@ function createMiddleware(server: ViteDevServer, options: DevServerOptions) { } const exclude = options.exclude ?? defaultOptions.exclude ?? []; + const urlPath = req.url?.split("?")[0]; for (const pattern of exclude) { if (req.url) { if (pattern instanceof RegExp) { - if (pattern.test(req.url)) { + if (pattern.test(req.url) || (urlPath && pattern.test(urlPath))) { return next(); } } else if (typeof pattern === "string") { - if (req.url.startsWith(pattern)) { + if (req.url.startsWith(pattern) || (urlPath && urlPath.startsWith(pattern))) { return next(); } } From 3c824f541ff640cd378a114175d2077eea1430cd Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Mon, 9 Feb 2026 14:05:56 -0800 Subject: [PATCH 2/2] refactor: test exclude patterns against path only, remove redundant ?import pattern --- src/dev-server.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/dev-server.ts b/src/dev-server.ts index d35dc68..3cbf3e9 100644 --- a/src/dev-server.ts +++ b/src/dev-server.ts @@ -29,7 +29,6 @@ export const defaultOptions: Partial = { /.*\.webp$/, /^\/@.+$/, /^\/node_modules\/.*/, - /\?import$/, ], injectClientScript: true, }; @@ -66,13 +65,13 @@ function createMiddleware(server: ViteDevServer, options: DevServerOptions) { const urlPath = req.url?.split("?")[0]; for (const pattern of exclude) { - if (req.url) { + if (urlPath) { if (pattern instanceof RegExp) { - if (pattern.test(req.url) || (urlPath && pattern.test(urlPath))) { + if (pattern.test(urlPath)) { return next(); } } else if (typeof pattern === "string") { - if (req.url.startsWith(pattern) || (urlPath && urlPath.startsWith(pattern))) { + if (urlPath.startsWith(pattern)) { return next(); } }