withastro / astro · Issue No. 18094
Astro v7.3.3
Vite v8.3.0
Node v25.0.0
System macOS (arm64)
Package Manager npm
Output server
Adapter @astrojs/node (v11.1.6)
Integrations @astrojs/svelte (v9.0.1)
Safari (Chromium usually hides it, see below). Reproducible in any browser via the script in the repro.
In astro dev, a server island containing a framework component (React, Svelte, Vue, …) renders empty when the project has a custom src/fetch.ts built on astro/fetch.
/_server-islands/<Name> response contains no component HTML, so the client replaces the fallback with nothing and leaves a blank hole.[NoMatchingRenderer] Unable to render 'Message' even though the integration is configured.src/fetch.ts and the same island renders correctly.Why it happens:
FetchState (astro/fetch) reads the manifest via getAmbientManifest(), i.e. the virtual:astro:manifest module export, rather than the stable app.manifest object.virtual:astro:manifest depends on virtual:astro:server-island-manifest, which the server islands plugin invalidates on every .astro/.mdx transform. Rendering the page invalidates it, so the next request gets a fresh manifest object with no renderers.createRunnableEnvironment (vite-plugin-app/environment.ts), getComponentByRoute returns early for built-in routes like /_server-islands/[name] before loading renderers into devRenderers. Renderers are only loaded when a user route renders, and only onto whichever manifest object that request used.NoMatchingRenderer.Why it looks browser-specific:
<link rel="preload" as="fetch"> for the island URL, so the island request starts while the page render is still in flight and shares its manifest. Works.<script> after page load. By then the manifest has been invalidated. Blank.Fix proposed in #18000: move the renderer-loading block ahead of the built-in route check in getComponentByRoute.
https://github.com/barclayd/astro-island-repro
npm install && npx astro dev, then npm run repro in another terminal (fetches the page, then the island, like Safari does). Prints FAIL on 7.3.3; delete src/fetch.ts and it prints PASS.
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.