Summary
Turnkey SSR development fails when the ssr environment is supplied by @cloudflare/vite-plugin because vite-plugin-solid calls the legacy server.ssrLoadModule() API, which only works with a RunnableDevEnvironment.
Cloudflare recommends assigning its Worker to the framework's SSR environment with viteEnvironment: { name: 'ssr' }. Its environment runs modules in workerd and is intentionally not runnable in the Vite server process.
Production builds and previews work; the failure is specific to development.
Versions
vite-plugin-solid: 3.0.0-next.15
vite: 8.1.5
solid-js: 2.0.0-beta.23
@solidjs/web: 2.0.0-beta.23
@cloudflare/vite-plugin: 1.46.0
wrangler: 4.113.0
Minimal reproduction
vite.config.ts:
import { cloudflare } from '@cloudflare/vite-plugin'
import { defineConfig } from 'vite'
import solid from 'vite-plugin-solid'
export default defineConfig({
plugins: [
cloudflare({ viteEnvironment: { name: 'ssr' } }),
solid({ ssr: {}, serverFunctions: true }),
],
})
wrangler.jsonc:
src/worker.ts:
import { handleRequest } from 'virtual:solid-ssr-handler'
export default {
fetch(request: Request) {
return handleRequest(request)
},
}
Add a basic src/App.tsx, run pnpm dev, and request / with Accept: text/html.
Actual behavior
Internal server error: ssrLoadModule requires the 'ssr' environment to be a runnable environment.
at ssrLoadModule (.../vite/dist/node/chunks/node.js)
at Proxy.ssrLoadModule (.../vite/dist/node/chunks/node.js)
at .../vite-plugin-solid/dist/esm/index.mjs
The call originates from the turnkey middleware in src/ssr/index.ts, which does:
const handler = await server.ssrLoadModule(HANDLER_ID)
The server-functions development middleware in src/server-functions/index.ts also calls server.ssrLoadModule() for both the referenced module and the virtual handler, so it appears to have the same environment limitation.
Expected behavior
Turnkey SSR should either dispatch through the environment's supported communication mechanism or defer to the runtime provider's middleware instead of assuming that ssr is runnable in the Vite server process.
The existing Worker entry already imports the adapter-agnostic virtual:solid-ssr-handler, so Cloudflare can execute the handler inside workerd if Solid's Node-oriented middleware delegates the request.
Verified production behavior
pnpm build succeeds and emits the Worker/server and client bundles.
pnpm preview returns 200 with server-rendered HTML from the Worker runtime.
Current workaround
Keeping the Cloudflare Worker out of the ssr environment during development leaves Vite's default runnable SSR environment available to Solid, while preserving the production environment merge:
export default defineConfig(({ command }) => ({
plugins: [
cloudflare({
viteEnvironment: command === 'build' ? { name: 'ssr' } : undefined,
}),
solid({ ssr: {}, serverFunctions: true }),
],
}))
This avoids the exception but means development does not follow the intended single Cloudflare SSR environment setup.
Possible direction
Use Vite's Environment API instead of server.ssrLoadModule():
- For
isRunnableDevEnvironment(environment), load virtual handlers with environment.runner.import().
- For a
FetchableDevEnvironment, dispatch the web request with environment.dispatchFetch().
- For a provider-owned raw environment such as Cloudflare's current environment, call
next() so the provider can route the request to its runtime.
- Apply equivalent capability handling to the server-functions development middleware and ensure the generated Worker handler can serve server-function requests in development.
An explicit turnkey option such as ssr.devMiddleware: false could also provide an adapter-controlled escape hatch, although automatic capability detection would avoid Cloudflare-specific configuration.
Summary
Turnkey SSR development fails when the
ssrenvironment is supplied by@cloudflare/vite-pluginbecausevite-plugin-solidcalls the legacyserver.ssrLoadModule()API, which only works with aRunnableDevEnvironment.Cloudflare recommends assigning its Worker to the framework's SSR environment with
viteEnvironment: { name: 'ssr' }. Its environment runs modules inworkerdand is intentionally not runnable in the Vite server process.Production builds and previews work; the failure is specific to development.
Versions
vite-plugin-solid:3.0.0-next.15vite:8.1.5solid-js:2.0.0-beta.23@solidjs/web:2.0.0-beta.23@cloudflare/vite-plugin:1.46.0wrangler:4.113.0Minimal reproduction
vite.config.ts:wrangler.jsonc:{ "$schema": "./node_modules/wrangler/config-schema.json", "name": "solid-cloudflare", "main": "./src/worker.ts", "compatibility_date": "2026-07-22", "compatibility_flags": ["nodejs_compat"], "assets": { "directory": "./dist/client", "binding": "ASSETS" } }src/worker.ts:Add a basic
src/App.tsx, runpnpm dev, and request/withAccept: text/html.Actual behavior
The call originates from the turnkey middleware in
src/ssr/index.ts, which does:The server-functions development middleware in
src/server-functions/index.tsalso callsserver.ssrLoadModule()for both the referenced module and the virtual handler, so it appears to have the same environment limitation.Expected behavior
Turnkey SSR should either dispatch through the environment's supported communication mechanism or defer to the runtime provider's middleware instead of assuming that
ssris runnable in the Vite server process.The existing Worker entry already imports the adapter-agnostic
virtual:solid-ssr-handler, so Cloudflare can execute the handler insideworkerdif Solid's Node-oriented middleware delegates the request.Verified production behavior
pnpm buildsucceeds and emits the Worker/server and client bundles.pnpm previewreturns200with server-rendered HTML from the Worker runtime.Current workaround
Keeping the Cloudflare Worker out of the
ssrenvironment during development leaves Vite's default runnable SSR environment available to Solid, while preserving the production environment merge:This avoids the exception but means development does not follow the intended single Cloudflare SSR environment setup.
Possible direction
Use Vite's Environment API instead of
server.ssrLoadModule():isRunnableDevEnvironment(environment), load virtual handlers withenvironment.runner.import().FetchableDevEnvironment, dispatch the web request withenvironment.dispatchFetch().next()so the provider can route the request to its runtime.An explicit turnkey option such as
ssr.devMiddleware: falsecould also provide an adapter-controlled escape hatch, although automatic capability detection would avoid Cloudflare-specific configuration.