Astro Info
Astro v6.4.3
Vite v7.3.5
Node v22.22.3
System Linux (x64)
Output server
Adapter @astrojs/cloudflare (v13.6.1)
Describe the Bug
When experimental.advancedRouting is an object with a fetchFile pointing at a worker that imports cf from @astrojs/cloudflare/fetch, the build crashes:
(0 , __vite_ssr_import_0__.createGetEnv) is not a function
at runInRunnerObject (workers/runner-worker/index.js:107:3)
With advancedRouting: true it builds fine, because virtual:astro:fetchable falls back to DefaultFetchHandler and never imports @astrojs/cloudflare/fetch.
It's a circular import. fetch.js runs setGetEnv(createGetEnv(globalEnv)) and createApp() at the top level. createApp comes from astro/app/entrypoint, which imports virtual:astro:fetchable, which re-exports my worker.ts, which imports @astrojs/cloudflare/fetch again. So fetch.js top-level runs while those modules are still mid-init, and the binding it reads is undefined.
You can tell it's the cycle and not bundling: nudging optimizeDeps just moves the error. Forcing @astrojs/cloudflare/fetch into optimizeDeps.include gives createGetEnv is not a function, exclude gives createApp is not a function. Same cycle, different binding read too early.
Workaround that fixes it, import cf lazily so worker.ts doesn't statically depend on it:
const { cf } = await import('@astrojs/cloudflare/fetch');
src/worker.ts that triggers it:
import { astro, FetchState } from 'astro/fetch';
import { cf } from '@astrojs/cloudflare/fetch';
export default {
async fetch(request, env, ctx) {
const state = new FetchState(request);
const asset = await cf(state, env, ctx);
if (asset) return asset;
return astro(state);
},
};
config:
experimental: { advancedRouting: { fetchFile: 'worker' } }
What's the expected result?
Build succeeds with a custom fetchFile that imports cf from @astrojs/cloudflare/fetch, like the docs pattern. Ideally fetch.js wouldn't fall over on the cycle, either don't run createApp() / setGetEnv() eagerly at module top level, or export createGetEnv as a hoisted function so it survives a half initialized cycle.
Link to Minimal Reproducible Example
https://github.com/skezo/astro-cf-repro
Participation
Astro Info
Describe the Bug
When
experimental.advancedRoutingis an object with afetchFilepointing at a worker that importscffrom@astrojs/cloudflare/fetch, the build crashes:With
advancedRouting: trueit builds fine, becausevirtual:astro:fetchablefalls back toDefaultFetchHandlerand never imports@astrojs/cloudflare/fetch.It's a circular import.
fetch.jsrunssetGetEnv(createGetEnv(globalEnv))andcreateApp()at the top level.createAppcomes fromastro/app/entrypoint, which importsvirtual:astro:fetchable, which re-exports myworker.ts, which imports@astrojs/cloudflare/fetchagain. Sofetch.jstop-level runs while those modules are still mid-init, and the binding it reads is undefined.You can tell it's the cycle and not bundling: nudging optimizeDeps just moves the error. Forcing
@astrojs/cloudflare/fetchintooptimizeDeps.includegivescreateGetEnv is not a function,excludegivescreateApp is not a function. Same cycle, different binding read too early.Workaround that fixes it, import
cflazily soworker.tsdoesn't statically depend on it:src/worker.tsthat triggers it:config:
What's the expected result?
Build succeeds with a custom
fetchFilethat importscffrom@astrojs/cloudflare/fetch, like the docs pattern. Ideallyfetch.jswouldn't fall over on the cycle, either don't runcreateApp()/setGetEnv()eagerly at module top level, or exportcreateGetEnvas a hoisted function so it survives a half initialized cycle.Link to Minimal Reproducible Example
https://github.com/skezo/astro-cf-repro
Participation