With remoteBindings enabled, vite build produces all output correctly and then hangs forever. The process never exits.
Environment
@cloudflare/vite-plugin@1.51.1
wrangler@4.120.0
vite@8.2.1
- TanStack Start, prerendering enabled
- Worker has 7 Durable Object bindings and D1/KV/VPC bindings with
"remote": true
Reproduction
Run a build with remoteBindings: true in the plugin options and prerendering enabled.
The remote connection is established fine (no error 10375, so #13956 is genuinely fixed — thank you). The prerender pass completes:
⎔ Establishing remote connection...
[prerender] Prerendering pages...
[prerender] Crawling: /
GET / 200 OK (89ms)
...
[prerender] Prerendered 117 pages:
Every file is written to dist/, the output is correct, and then the process just sits there. It has to be killed manually.
Cause
startRemoteProxySession in wrangler creates a full DevEnv with a listening server:
const workerConfig = {
name: options.workerName ?? crypto2.randomUUID(),
entrypointSource: ProxyServerWorker_default,
...
server: { port: 0, secure: false }
};
let devEnv;
try {
devEnv = new DevEnv(workerConfig);
devEnv.start();
}
That listening server is a referenced libuv handle, so Node's event loop cannot drain while it stays open.
On the plugin side, sessions are kept in a module-level map:
/** Map that maps worker configPaths to their existing remote proxy session data (if any) */
const remoteProxySessionsDataMap = new Map();
Grepping the built plugin (dist/index.mjs of 1.51.1), that map has 2 gets and 2 sets (one pair on the dev server path, one on the preview server path) and zero deletes. The only session.dispose() call in the whole bundle is:
if (!authSameAsBefore) {
if (preExistingRemoteProxySessionData?.session)
await preExistingRemoteProxySessionData.session.dispose();
remoteProxySession = await startSession(remoteBindings, { ... });
}
It only fires to replace a session when auth changes. There is no teardown when the preview server closes or when the build ends.
For vite dev this is invisible, since the server runs until you interrupt it. For vite build, the preview server exists only to serve the prerender pass, so once the pass finishes nothing disposes the session and the build hangs.
Expected
The preview server's remote proxy session should be disposed when the build completes, so vite build exits normally.
Impact
Remote bindings cannot be used in any CI build. That rules out prerendering pages against real data, which is otherwise exactly what remote bindings make possible. In our case the prerendered output was perfect (real values from D1 dehydrated into the static HTML) and the only thing standing in the way is the process not exiting.
I could not find an existing issue for this, and the 1.52.0 changelog does not appear to touch session disposal or build exit.
With
remoteBindingsenabled,vite buildproduces all output correctly and then hangs forever. The process never exits.Environment
@cloudflare/vite-plugin@1.51.1wrangler@4.120.0vite@8.2.1"remote": trueReproduction
Run a build with
remoteBindings: truein the plugin options and prerendering enabled.The remote connection is established fine (no error 10375, so #13956 is genuinely fixed — thank you). The prerender pass completes:
Every file is written to
dist/, the output is correct, and then the process just sits there. It has to be killed manually.Cause
startRemoteProxySessionin wrangler creates a fullDevEnvwith a listening server:That listening server is a referenced libuv handle, so Node's event loop cannot drain while it stays open.
On the plugin side, sessions are kept in a module-level map:
Grepping the built plugin (
dist/index.mjsof 1.51.1), that map has 2gets and 2sets (one pair on the dev server path, one on the preview server path) and zerodeletes. The onlysession.dispose()call in the whole bundle is:It only fires to replace a session when auth changes. There is no teardown when the preview server closes or when the build ends.
For
vite devthis is invisible, since the server runs until you interrupt it. Forvite build, the preview server exists only to serve the prerender pass, so once the pass finishes nothing disposes the session and the build hangs.Expected
The preview server's remote proxy session should be disposed when the build completes, so
vite buildexits normally.Impact
Remote bindings cannot be used in any CI build. That rules out prerendering pages against real data, which is otherwise exactly what remote bindings make possible. In our case the prerendered output was perfect (real values from D1 dehydrated into the static HTML) and the only thing standing in the way is the process not exiting.
I could not find an existing issue for this, and the
1.52.0changelog does not appear to touch session disposal or build exit.