[PR #344] [MERGED] fix: middleware crash in dev mode with cloudflare plugin #498

Closed
opened 2026-05-06 13:08:23 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/344
Author: @james-elicx
Created: 3/8/2026
Status: Merged
Merged: 3/8/2026
Merged by: @james-elicx

Base: mainHead: j-branch-3


📝 Commits (3)

  • 27d314a test: middleware with cloudflare plugin and routing bypass
  • 6617773 fix: use module runner for pages middleware
  • 70c2fc8 add pages router dev test

📊 Changes

22 files changed (+883 additions, -129 deletions)

View changed files

📝 .github/workflows/ci.yml (+1 -0)
examples/app-router-cloudflare/middleware.ts (+14 -0)
examples/pages-router-cloudflare/instrumentation-state.ts (+144 -0)
examples/pages-router-cloudflare/instrumentation.ts (+27 -0)
examples/pages-router-cloudflare/middleware.ts (+17 -0)
examples/pages-router-cloudflare/pages/api/error-route.ts (+7 -0)
examples/pages-router-cloudflare/pages/api/instrumentation-test.ts (+29 -0)
📝 examples/pages-router-cloudflare/pages/ssr.tsx (+8 -2)
📝 packages/vinext/src/index.ts (+75 -5)
packages/vinext/src/server/dev-module-runner.ts (+137 -0)
📝 packages/vinext/src/server/instrumentation.ts (+21 -7)
📝 packages/vinext/src/server/middleware.ts (+12 -6)
📝 playwright.config.ts (+22 -1)
tests/e2e/cloudflare-dev/middleware.spec.ts (+89 -0)
tests/e2e/cloudflare-pages-router-dev/middleware.spec.ts (+91 -0)
tests/e2e/cloudflare-pages-router-dev/pages-router.spec.ts (+25 -0)
tests/e2e/cloudflare-pages-router/middleware.spec.ts (+44 -0)
tests/e2e/pages-router/instrumentation-startup.spec.ts (+48 -0)
📝 tests/e2e/pages-router/instrumentation.spec.ts (+23 -59)
📝 tests/features.test.ts (+17 -17)

...and 2 more files

📄 Description

Adds regression tests for two bugs that occur when @cloudflare/vite-plugin is present alongside middleware.ts.

Bug 1 — outsideEmitter crash

The connect handler called runMiddleware()server.ssrLoadModule(), which constructs an SSRCompatModuleRunner. That runner requires a hot channel that doesn't exist in the host process when the Cloudflare plugin is loaded, crashing immediately with:

TypeError: Cannot read properties of undefined (reading 'outsideEmitter')

Fixed by switching to createDirectRunner(), which calls environment.fetchModule() directly and never touches the hot channel.

Bug 2 — requests intercepted before reaching the Worker

After the crash was resolved, the connect handler was still calling createSSRHandler() for any Pages Router route match, rendering pages in the host process instead of dispatching to the Cloudflare Worker. Routes like / that matched both a pages/ stub and an app/ route were served by the host instead of miniflare.

Fixed by the hasCloudflarePlugin early-return: after middleware runs, the connect handler calls next() unconditionally, handing off to the Cloudflare plugin.

How the tests assert Worker execution

  • /api/hello returns navigator.userAgent"Cloudflare-Workers" inside miniflare, absent or wrong if intercepted by the host.
  • / has competing handlers: app/page.tsx renders "vinext on Cloudflare Workers", pages/index.tsx renders "pages index". The wrong text appearing means the Worker was bypassed.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/344 **Author:** [@james-elicx](https://github.com/james-elicx) **Created:** 3/8/2026 **Status:** ✅ Merged **Merged:** 3/8/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `j-branch-3` --- ### 📝 Commits (3) - [`27d314a`](https://github.com/cloudflare/vinext/commit/27d314a8957091286547f4fd9185b032a5342250) test: middleware with cloudflare plugin and routing bypass - [`6617773`](https://github.com/cloudflare/vinext/commit/66177734fb2b257e69a145ae7636003c6432408c) fix: use module runner for pages middleware - [`70c2fc8`](https://github.com/cloudflare/vinext/commit/70c2fc87f4619723ef9da0cb9516d93b2e25f140) add pages router dev test ### 📊 Changes **22 files changed** (+883 additions, -129 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/ci.yml` (+1 -0) ➕ `examples/app-router-cloudflare/middleware.ts` (+14 -0) ➕ `examples/pages-router-cloudflare/instrumentation-state.ts` (+144 -0) ➕ `examples/pages-router-cloudflare/instrumentation.ts` (+27 -0) ➕ `examples/pages-router-cloudflare/middleware.ts` (+17 -0) ➕ `examples/pages-router-cloudflare/pages/api/error-route.ts` (+7 -0) ➕ `examples/pages-router-cloudflare/pages/api/instrumentation-test.ts` (+29 -0) 📝 `examples/pages-router-cloudflare/pages/ssr.tsx` (+8 -2) 📝 `packages/vinext/src/index.ts` (+75 -5) ➕ `packages/vinext/src/server/dev-module-runner.ts` (+137 -0) 📝 `packages/vinext/src/server/instrumentation.ts` (+21 -7) 📝 `packages/vinext/src/server/middleware.ts` (+12 -6) 📝 `playwright.config.ts` (+22 -1) ➕ `tests/e2e/cloudflare-dev/middleware.spec.ts` (+89 -0) ➕ `tests/e2e/cloudflare-pages-router-dev/middleware.spec.ts` (+91 -0) ➕ `tests/e2e/cloudflare-pages-router-dev/pages-router.spec.ts` (+25 -0) ➕ `tests/e2e/cloudflare-pages-router/middleware.spec.ts` (+44 -0) ➕ `tests/e2e/pages-router/instrumentation-startup.spec.ts` (+48 -0) 📝 `tests/e2e/pages-router/instrumentation.spec.ts` (+23 -59) 📝 `tests/features.test.ts` (+17 -17) _...and 2 more files_ </details> ### 📄 Description Adds regression tests for two bugs that occur when `@cloudflare/vite-plugin` is present alongside `middleware.ts`. **Bug 1 — `outsideEmitter` crash** The connect handler called `runMiddleware()` → `server.ssrLoadModule()`, which constructs an `SSRCompatModuleRunner`. That runner requires a hot channel that doesn't exist in the host process when the Cloudflare plugin is loaded, crashing immediately with: ``` TypeError: Cannot read properties of undefined (reading 'outsideEmitter') ``` Fixed by switching to `createDirectRunner()`, which calls `environment.fetchModule()` directly and never touches the hot channel. **Bug 2 — requests intercepted before reaching the Worker** After the crash was resolved, the connect handler was still calling `createSSRHandler()` for any Pages Router route match, rendering pages in the host process instead of dispatching to the Cloudflare Worker. Routes like `/` that matched both a `pages/` stub and an `app/` route were served by the host instead of miniflare. Fixed by the `hasCloudflarePlugin` early-return: after middleware runs, the connect handler calls `next()` unconditionally, handing off to the Cloudflare plugin. **How the tests assert Worker execution** - `/api/hello` returns `navigator.userAgent` — `"Cloudflare-Workers"` inside miniflare, absent or wrong if intercepted by the host. - `/` has competing handlers: `app/page.tsx` renders `"vinext on Cloudflare Workers"`, `pages/index.tsx` renders `"pages index"`. The wrong text appearing means the Worker was bypassed. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:08:23 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#498
No description provided.