Repository navigation
fix(pages): link CSS that island and Markdown pages reach through components - #481
Brooooooklyn wants to merge 1 commit into
Conversation
…ponents In production, island and Markdown pages only got the CSS their page and layout files import directly. A stylesheet imported by a component that a layout renders was missing, and when no file imported CSS directly the islands client entry was not built at all, so no page got a stylesheet. - Build the islands client entry for every app with island or Markdown pages, replacing the text scan in needsIslandClientBundle. - Record the stylesheets that island pages and their layouts reach through static imports from the server build's module graph, and import them in the islands client entry. This covers aliases, packages, CSS modules and Vue/Svelte style blocks, and keeps the CSS order of dev. - Keep CSS modules that the entry imports (Vite marks them side-effect free), keep Vue scoped styles whose component is not in the client bundle, and load Svelte styles through vite-plugin-svelte's own id so a rule is not emitted twice. - Without islands, the entry only holds the CSS imports, so no hydration runtime is bundled. The React and Solid entry is now added only to the client build. Fixes #452 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
🚀 Deploying Preview to Cloudflare 🚀Preview URL: https://fix-island-transitive-css-void-cloud.voidzero-docs.workers.dev (commit 331e23b)This URL reflects your latest Preview deploymentPreview Deployments by commit
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 331e23bff7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const imported = getModuleInfo(id)?.importedIds ?? []; | ||
| for (let index = imported.length - 1; index >= 0; index--) { | ||
| pending.push(imported[index]); |
There was a problem hiding this comment.
Collect styles using the client-side dependency graph
For Node/Bun/Deno builds, a layout can import a package whose conditional server entry renders the component while its browser entry imports the stylesheet. The SSR build externalizes ordinary installed packages, so getModuleInfo() returns no traversable imports here; consequently the stylesheet is absent from styles, and because the islands entry imports only that recorded list, production island/Markdown pages lose CSS that the dev client graph applies. The collection needs to account for client-resolved package dependencies rather than relying exclusively on the server graph.
AGENTS.md reference: packages/void/AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Not changing this in this PR. Reasons:
- Dev doesn't do it either. The dev CSS collector (
packages/void/src/pages/dev-css-assets.ts,visit) stops at pre-bundled packages (if (isOptimizedDepUrl(node.url)) return;). So CSS that a package's own JS imports is not linked at first paint in dev either. This PR matches dev; it does not fall behind it. - It never worked before. On
mainonly the direct CSS imports of pages and layouts were bundled, so a stylesheet imported inside a package's JS was never linked on island pages, on any target. - What does work: a page, layout or app component that imports a package stylesheet directly (
import 'ui-lib/style.css'). CSS imports go through Vite's CSS pipeline in the server build and are not externalized, so they are in the recorded list on the Node target too. On Cloudflare, packages are bundled, so their CSS imports are followed as well.
Following client-resolved package graphs for island pages would be a new feature for both dev and build: it means loading package entries in the client build only to inspect them. That's a separate change from #452, which is about the app's own components.
Fixes #452
Problem
vp devappliedglobal.css. A production build did not:<style>or island import (a text scan). With CSS only reachable through a component, no client build ran, so pages got no<link rel="stylesheet">.Fix
hasIslandPages). It replaces theneedsIslandClientBundletext scan, which only the adapters used.?inline/?url/?raware skipped.*.module.css, Vue<style module>) are kept. Vite marks them side-effect free, so the bare import would drop them.cssScopeTois cleared for the recorded ids, because the component itself is not in the client bundle.?svelte&type=styleid, compiled through the existing island-style loader, so the same rule is not emitted twice in mixed apps.<link>, no<script>.Behaviour changes worth knowing
<style scoped>used to fail the build (PARSE_ERRORon...&scoped=true). It now builds and links the CSS.playground/markdown-blog: same CSS rules, but@void/md/theme.css(imported in the script) now comes before the layout's<style>, which is Vue's normal order.Known limit (unchanged, not in this PR)
In apps with both island and regular pages,
collectRouteCss(routing-assets.ts) puts a chunk's own CSS before the CSS of chunks it imports, so the islands stylesheet can come before shared layout CSS. That order already applied to direct page CSS onmain. Changing it would change the link order on every page.Tests
New production-build tests for each adapter (
packages/{react,vue,svelte,solid}/test/integration/island-css-build.test.ts, sharedtest/island-css-build.ts). Each one builds a static app where a layout renders a component that imports CSS, with an island page and a Markdown page, and checks:<style>, Vue scoped with matchingdata-v-*, Svelte matchingsvelte-*class) appears exactly once;<script>;hydrateRoot, anddist/ssrhas no islands client.Plus unit tests for
collectIslandStylesandislandStyleRoots(order, no repeats,\0ids,?inline/?url).mainsourcesvp fmt --check,vp lint, typecheck void/react/vue/svelte/solid🤖 Generated with Claude Code