Skip to content

fix(vite-plugin-cloudflare): add hot channel api for ssrLoadModule compatibility#12738

Closed
hyf0 wants to merge 1 commit intocloudflare:mainfrom
hyf0:fix/cloudflare-dev-environment-hot-api
Closed

fix(vite-plugin-cloudflare): add hot channel api for ssrLoadModule compatibility#12738
hyf0 wants to merge 1 commit intocloudflare:mainfrom
hyf0:fix/cloudflare-dev-environment-hot-api

Conversation

@hyf0
Copy link
Copy Markdown

@hyf0 hyf0 commented Mar 3, 2026

Summary

CloudflareDevEnvironment's hot channel is missing the api property (innerEmitter / outsideEmitter), which causes server.ssrLoadModule() to crash when called by other Vite plugins on a dev server where @cloudflare/vite-plugin is active:

TypeError: Cannot read properties of undefined (reading 'outsideEmitter')
    at Object.connect (createServerModuleRunnerTransport)
    at new SSRCompatModuleRunner
    at ssrLoadModule

Root cause

ssrLoadModule() creates an SSRCompatModuleRunner whose transport accesses environment.hot.api.outsideEmitter. Vite's built-in createServerHotChannel() (used by RunnableDevEnvironment) provides this api property, but CloudflareDevEnvironment's createHotChannel() does not.

The HotChannel interface defines api as optional (api?: Api), but createServerModuleRunnerTransport unconditionally accesses it.

Fix

Add api: { innerEmitter, outsideEmitter } to createHotChannel(), matching what createServerHotChannel() provides. This makes CloudflareDevEnvironment compatible with ssrLoadModule() without changing its existing WebSocket-based module execution.

Use case

Framework plugins that perform SSG/prerendering call server.ssrLoadModule() during build to execute exports from page files (e.g. collecting prerender paths for static site generation). When @cloudflare/vite-plugin is present in the user's config, this crashes because the SSR environment is a CloudflareDevEnvironment with an incomplete hot channel.

Related

…mpatibility

CloudflareDevEnvironment's hot channel was missing the `api` property
with `innerEmitter`/`outsideEmitter` that `ssrLoadModule()` requires.
When another Vite plugin (e.g. a framework's SSG prerender step) calls
`server.ssrLoadModule()` on a dev server where @cloudflare/vite-plugin
is active, the SSRCompatModuleRunner's transport crashes:

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

The `HotChannel` interface defines `api` as optional, but
`createServerModuleRunnerTransport` unconditionally accesses
`channel.api.outsideEmitter`. Vite's built-in `createServerHotChannel()`
(used by `RunnableDevEnvironment`) includes `api` — this aligns
`CloudflareDevEnvironment`'s hot channel to do the same.

Related: vitejs/vite#21726, vitejs/vite#21739

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 3, 2026 07:53
@hyf0 hyf0 requested a review from a team as a code owner March 3, 2026 07:53
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 3, 2026

⚠️ No Changeset found

Latest commit: dc09362

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@workers-devprod
Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/wrangler
Show detailed file reviewers
  • packages/vite-plugin-cloudflare/src/cloudflare-environment.ts: [@cloudflare/wrangler]

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a compatibility gap between @cloudflare/vite-plugin’s dev environment and Vite’s server.ssrLoadModule() by aligning CloudflareDevEnvironment’s hot channel with what Vite’s server-side module runner expects.

Changes:

  • Add hot.api to the Cloudflare hot channel (innerEmitter / outsideEmitter) to match Vite’s server hot channel shape.
  • Emit outsideEmitter "send" events when sending payloads, and emit innerEmitter "connection" when the channel starts listening.
  • Clean up emitter listeners on hot channel close().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

@hyf0
Copy link
Copy Markdown
Author

hyf0 commented Mar 3, 2026

Closing — adding api to the hot channel prevents the crash but doesn't make ssrLoadModule actually work, since CloudflareDevEnvironment still requires a running Miniflare backend to execute modules. The transport times out waiting for a worker that was never started. The fix belongs on the caller's side (overriding createEnvironment to use createRunnableDevEnvironment).

@hyf0 hyf0 closed this Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants