Skip to content

Preserve renderers for discovered server islands#15950

Merged
matthewp merged 4 commits intomainfrom
si-w-ci
Mar 19, 2026
Merged

Preserve renderers for discovered server islands#15950
matthewp merged 4 commits intomainfrom
si-w-ci

Conversation

@matthewp
Copy link
Copy Markdown
Contributor

@matthewp matthewp commented Mar 16, 2026

Changes

Testing

  • Test in cloudflare
  • Added unit tests for discovery deduplication, name collision handling, and import/name map generation in ServerIslandsState.

Docs

  • No docs update needed. This is an internal bug fix/refactor with no API or config changes.

Refactors server-island tracking into a shared state class and uses it to prevent SSR renderer stripping for prerender-only pages with server islands.
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 16, 2026

🦋 Changeset detected

Latest commit: 378b86a

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added pkg: integration Related to any renderer integration (scope) pkg: astro Related to the core `astro` package (scope) labels Mar 16, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 16, 2026

Merging this PR will not alter performance

✅ 18 untouched benchmarks


Comparing si-w-ci (378b86a) with main (1e6017f)

Open in CodSpeed

@matthewp matthewp changed the title fix(server-islands): preserve renderers for discovered server islands Preserve renderers for discovered server islands Mar 16, 2026
@matthewp matthewp marked this pull request as ready for review March 16, 2026 21:00
Copy link
Copy Markdown
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new state management lacks in docs and tests. I would like to see more of that, because at the moment I don't really understand the new logic

Comment on lines +93 to +95
resolvedPath: comp.resolvedPath,
localName: comp.localName,
specifier: comp.specifier ?? comp.resolvedPath,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If resolvedPath and specifier match, wouldn't make more sense to have specifier being null/undefined and fallback to resolvedPath?

Since we're poor on comments (can't understand the difference between the two fields), it seems the only logical suggestion

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specifier is the import from './foo' the ./foo part. We already had this fallback, i'll add a comment explaining.

Comment on lines +25 to +28
assert.equal(state.hasIslands(), true);
assert.equal(first.islandName, 'Island');
assert.deepEqual(duplicate, first);
assert.equal(Array.from(state.getDiscoveredIslands()).length, 1);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's one thing we should document in the discover method (or class): what deems an island being a duplicate or not. Is it the resolvedPath and specifier?

Then, we should add a test against "not deep equal". That will cement the logic of "being e duplicate"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it's resolvedPath, added a test.

'astro': patch
---

Fixes a build regression where SSR framework renderers could be removed when all project pages are prerendered, causing `server:defer` server islands to fail at runtime.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think users have a grasp of "renderers", which is an internal term. Maybe let's say something like "having multiple frontend integrations could lead..."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renderer is not internal, it's used in public APIs, for example: https://docs.astro.build/en/reference/integrations-reference/#addrenderer-option

I feel like this is a good use of the term, otherwise I'm not sure what else you would say.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't know that! Even so, I believe docs wise we don't call it SSR anymore, but on demand pages. Unless you meant server renderer, which makes sense

Copy link
Copy Markdown
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a comment

}

const record: ServerIslandRecord = {
...island,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

island here still contains resolvedPath. I believe it's a TS bug that can't catch it. We should probably use a spread

const { resolvedPath: _, ...islandRecord } = island;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@matthewp matthewp merged commit acce5e8 into main Mar 19, 2026
27 checks passed
@matthewp matthewp deleted the si-w-ci branch March 19, 2026 18:09
@astrobot-houston astrobot-houston mentioned this pull request Mar 19, 2026
dadezzz pushed a commit to dadezzz/ice-notes that referenced this pull request Mar 24, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [astro](https://astro.build) ([source](https://github.com/withastro/astro/tree/HEAD/packages/astro)) | [`6.0.6` → `6.0.8`](https://renovatebot.com/diffs/npm/astro/6.0.6/6.0.8) | ![age](https://developer.mend.io/api/mc/badges/age/npm/astro/6.0.8?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/astro/6.0.6/6.0.8?slim=true) |

---

### Release Notes

<details>
<summary>withastro/astro (astro)</summary>

### [`v6.0.8`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#608)

[Compare Source](https://github.com/withastro/astro/compare/astro@6.0.7...astro@6.0.8)

##### Patch Changes

- [#&#8203;15978](withastro/astro#15978) [`6d182fe`](withastro/astro@6d182fe) Thanks [@&#8203;seroperson](https://github.com/seroperson)! - Fixes a bug where Astro Actions didn't properly support nested object properties, causing problems when users used zod functions such as `superRefine` or `discriminatedUnion`.

- [#&#8203;16011](withastro/astro#16011) [`e752170`](withastro/astro@e752170) Thanks [@&#8203;matthewp](https://github.com/matthewp)! - Fixes a dev server hang on the first request when using the Cloudflare adapter

- [#&#8203;15997](withastro/astro#15997) [`1fddff7`](withastro/astro@1fddff7) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixes `Astro.rewrite()` failing when the target path contains duplicate slashes (e.g. `//about`). The duplicate slashes are now collapsed before URL parsing, preventing them from being interpreted as a protocol-relative URL.

### [`v6.0.7`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#607)

[Compare Source](https://github.com/withastro/astro/compare/astro@6.0.6...astro@6.0.7)

##### Patch Changes

- [#&#8203;15950](withastro/astro#15950) [`acce5e8`](withastro/astro@acce5e8) Thanks [@&#8203;matthewp](https://github.com/matthewp)! - Fixes a build regression in projects with multiple frontend integrations where `server:defer` server islands could fail at runtime when all pages are prerendered.

- [#&#8203;15988](withastro/astro#15988) [`c93b4a0`](withastro/astro@c93b4a0) Thanks [@&#8203;ossaidqadri](https://github.com/ossaidqadri)! - Fix styles from dynamically imported components not being injected on first dev server load.

- [#&#8203;15968](withastro/astro#15968) [`3e7a9d5`](withastro/astro@3e7a9d5) Thanks [@&#8203;chasemccoy](https://github.com/chasemccoy)! - Fixes `renderMarkdown` in custom content loaders not resolving images in markdown content. Images referenced in markdown processed by `renderMarkdown` are now correctly optimized, matching the behavior of the built-in `glob()` loader.

- [#&#8203;15990](withastro/astro#15990) [`1e6017f`](withastro/astro@1e6017f) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixes an issue where `Astro.currentLocale` would always be the default locale instead of the actual one when using a dynamic route like `[locale].astro` or `[locale]/index.astro`. It now resolves to the correct locale from the URL.

- [#&#8203;15990](withastro/astro#15990) [`1e6017f`](withastro/astro@1e6017f) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixes an issue where visiting an invalid locale URL (e.g. `/asdf/`) would show the content of a dynamic `[locale]` page with a 404 status code, instead of showing your custom 404 page. Now, the correct 404 page is rendered when the locale in the URL doesn't match any configured locale.

- [#&#8203;15960](withastro/astro#15960) [`1d84020`](withastro/astro@1d84020) Thanks [@&#8203;matthewp](https://github.com/matthewp)! - Fixes Cloudflare dev server islands with `prerenderEnvironment: 'node'` by sharing the serialized manifest encryption key across dev environments and routing server island requests through the SSR runtime.

- [#&#8203;15735](withastro/astro#15735) [`9685e2d`](withastro/astro@9685e2d) Thanks [@&#8203;fa-sharp](https://github.com/fa-sharp)! - Fixes an EventEmitter memory leak when serving static pages from Node.js middleware.

  When using the middleware handler, requests that were being passed on to Express / Fastify (e.g. static files / pre-rendered pages / etc.) weren't cleaning up socket listeners before calling `next()`, causing a memory leak warning. This fix makes sure to run the cleanup before calling `next()`.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My43Ni4yIiwidXBkYXRlZEluVmVyIjoiNDMuODYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Renovate Bot <renovate@zarantonello.dev>
Co-committed-by: Renovate Bot <renovate@zarantonello.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: astro Related to the core `astro` package (scope) pkg: integration Related to any renderer integration (scope)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v6]: UI framework component inside server island is not rendered

2 participants