-
-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Description
ssrLoadModule() crashes with TypeError: Cannot read properties of undefined (reading 'outsideEmitter') when the SSR environment is a FetchableDevEnvironment (e.g. created by @cloudflare/vite-plugin with viteEnvironment: { name: "ssr" }).
Reproduction
import { createServer } from 'vite'
// User's vite.config includes @cloudflare/vite-plugin with
// viteEnvironment: { name: "ssr" }, which replaces the SSR
// environment with a FetchableDevEnvironment (CloudflareDevEnvironment)
const server = await createServer({
root: '/path/to/project',
server: { middlewareMode: true },
})
// This crashes:
await server.ssrLoadModule('/path/to/module.ts')Root Cause
SSRCompatModuleRunner unconditionally creates a transport that accesses environment.hot.api.outsideEmitter, but FetchableDevEnvironment's hot channel doesn't have the api property.
Call chain
-
ssrLoadModule()(ssrModuleLoader.ts) lazily createsSSRCompatModuleRunner:server._ssrCompatModuleRunner ||= new SSRCompatModuleRunner(environment)
-
SSRCompatModuleRunnerconstructor unconditionally passesenvironment.hotto the transport:super({ transport: createServerModuleRunnerTransport({ channel: environment.hot }), // ... })
-
createServerModuleRunnerTransportconnect()accessesapiwithout a null check:connect({ onMessage }) { options.channel.api.outsideEmitter.on("send", onMessage) // 💥 api is undefined }
Why api is missing
RunnableDevEnvironmentworks becausecreateRunnableDevEnvironment()callscreateServerHotChannel(), which creates the channel withapi: { innerEmitter, outsideEmitter }.FetchableDevEnvironmentextendsDevEnvironmentdirectly. Its hot channel is initialized vianormalizeHotChannel({}, context.hot)which spreads an empty object — noapiproperty.
Note
createHMROptions() already has the right guard:
if (!("api" in environment.hot)) return falseThis correctly disables HMR, but the transport is still created and its connect() method is called in the ModuleRunner constructor regardless.
Expected Behavior
ssrLoadModule() should work with any dev environment type, including FetchableDevEnvironment. Either:
SSRCompatModuleRunnershould check forapibefore creating the transportcreateServerModuleRunnerTransportconnect()should handle missingapigracefully- The
ModuleRunnerconstructor should not callconnect()when HMR is disabled
Environment
- Vite:
8.0.0-beta.14 @cloudflare/vite-plugin:1.25.6