fix: name the client entry in virtual:solid-manifest instead of guessing it (#353) - #354
Merged
Conversation
…ing it
With filesystem-routing's `fileRoutes({ routers: { client }, buildInputs:
'client' })` every route module is a configured client build input, and
since #347 (next.40) those manifest records rightly keep `isEntry`. The
generated start-mode handler resolved the client entry by taking the first
`isEntry` record in manifest key order, so a `src/routes/...` key sorting
ahead of `virtual:solid-ssr-entry-client.tsx` won: the document booted the
route chunk (no hydration) and <head> linked the route's CSS while the
entry graph's global stylesheet was never linked (#353).
The plugin knows which input is the application entry — start mode injects
it — so the manifest module now says so: `_entry` carries the entry's key
(the start-mode entry reported by startServe, or the single configured
input outside start mode) and the entry record is serialized first, so
@solidjs/web's registerEntryAssets (first-`isEntry` scan) links the same
chunk's CSS/preload graph. resolveClientEntry() reads `_entry` and keeps
the scan only as the fallback for hand-rolled manifests. Other configured
inputs keep `isEntry`.
Regression test: start-ssr `extra-input` mode builds with an additional
configured client input that App.tsx also lazily imports and asserts the
entry stylesheet is linked, the module script is the real entry chunk, and
the extra input's chunk is neither.
Closes #353
🦋 Changeset detectedLatest commit: 38434e1 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
commit: |
This was referenced Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #353
Problem
Regression from #347 (shipped in 3.0.0-next.40). With filesystem-routing's
fileRoutes({ routers: { client }, buildInputs: 'client' })every route module becomes a configuredbuild.rollupOptions.input; since #347 those manifest records rightly keepisEntry(they are genuine entries). The generated start-mode handler'sresolveClientEntry()picked the firstisEntryrecord in manifest key order — andsrc/routes/...sorts ahead ofvirtual:solid-ssr-entry-client.tsx.Confirmed with the issue's repro on next.40 (dumping the generated handler): it picks
src/routes/index.tsx?pick=default&pick=$css&lang.tsx. Consequences:<script type="module" src="/assets/index-Bm1I8-o3.js" async>— the route chunk is booted as the client entry, so the page never hydrates (worse than the reported CSS symptom).<head>links the route's CSS (index-BDXsaL_t.css) and the modulepreload graph of the route; the entry graph's global stylesheet (virtual_solid-ssr-entry-client-*.css) is never linked — the "1 stylesheet link / linked in head: false" in the report.@solidjs/web'sregisterEntryAssetshas the same first-isEntryscan, which is why the CSS/preload set was the route's too.Fix
Stop guessing. The plugin knows the entry it injected:
startServereports the client input it adds (virtual:solid-ssr-entry-client.tsxor the authored entry's absolute path) to the main plugin via a new internalonClientEntryResolvedcallback.virtual:solid-manifest(build flavor) now stampsmanifest._entry = <key>(matched by key orrecord.src, same spellings asisConfiguredEntry) and serializes the entry's record first, so consumers that still identify the entry by the firstisEntryrecord (@solidjs/web'sregisterEntryAssets, hand-rolled server entries) agree with_entry. Outside start mode_entryderives from the single configured input when there is exactly one (incl. Vite's defaultindex.html); with several inputs and no start entry it is left absent.resolveClientEntry()reads_entryfirst and only falls back to the first-isEntryscan when the stamp is absent. Stale "exactly one real entry remains flagged" comment replaced.isEntry.ViteManifesttype gains_entry?: string.The dev flavor of the manifest is a resolver (no records), so nothing to stamp there;
registerEntryAssetsalready returns early for it.Regression test
examples/start-ssrgains anextra-inputmode (EXTRA_CLIENT_INPUT=1):src/ExtraInput.tsx(with its own CSS) is both an extra configured client input and lazily imported byApp.tsx— thebuildInputsshape. Asserts on the built SSR output that the entry<link rel="stylesheet">is present, the<script type="module" src>is the real entry chunk, the extra input's chunk is neither, the baked manifest carries_entryand keeps the extra input flagged, and the extra input still works as a lazy route (both stylesheets). 3/8 onnext, 8/8 with the fix.Issue repro against a packed tarball:
linked in <head>: true,stylesheet links: 2, script tag is the real entry.Gate (local)
ssr 12/12 + boundary 8/8 · css-matrix 87/87 + bridge 19/19 · start-ssr 508/508 + http-bridge 10/10 + components-warning 9/9 · start-client 45/45 · start-env 47/47 · vite-8 vitest 1/1 · cypress 1/1.
Follow-up for
@solidjs/web(not needed for this fix):registerEntryAssetscould readmanifest._entrydirectly instead of relying on record order.