Skip to content

Keep genuine configured entries when reclassifying emitted lazy facades - #347

Merged
ryansolid merged 1 commit into
nextfrom
fix-342-entry-normalization
Sep 5, 2026
Merged

Keep genuine configured entries when reclassifying emitted lazy facades#347
ryansolid merged 1 commit into
nextfrom
fix-342-entry-normalization

Conversation

@ryansolid

Copy link
Copy Markdown
Member

Fixes #342

Root cause

normalizeEmittedLazyEntries cleared isEntry on every chunk that is any dynamic-import target. The real client entry becomes one as soon as it absorbs a module that is also dynamically imported: with Solid 2, @solidjs/web/frames/client lazily imports the serialization decoder (loadCodec()), so a static import of @solidjs/web/serialization/decode anywhere in the client graph merges the decoder into the entry chunk and the entry lists itself under dynamicImports. The genuine entry was then demoted, and downstream manifest capture (TanStack Start, TanStack/router#8214) failed with "No entry file found".

Rolldown wrinkle (why the chunk ended up isEntry=false isDynamicEntry=false): rolldown hands each plugin's generateBundle a fresh proxy over the native chunk; writes land in a per-hook JS cache and are synced back through update_output_chunk, which only copies code, map, imports, dynamicImports, isEntry and the file name — is_dynamic_entry is kept from the original chunk. So isEntry = false sticks but isDynamicEntry = true is discarded before the next plugin (and Vite's native manifest plugin) sees the bundle. That's a rolldown limitation no plugin-side write can work around; the plugin now repairs the flag in the one artifact it fully controls, virtual:solid-manifest.

Fix

  • Derive the genuine entries from the configured build input (rollupOptions/rolldownOptions input in string/array/record form, lib.entry, or Vite's default index.html — the start-mode virtual client entry included), in every spelling a facade id can take (as written, root-resolved, realpath).
  • generateBundle: never demote a chunk whose facadeModuleId matches a configured entry; ignore a chunk's dynamic import of itself; emitted lazy() facades are still reclassified by their emit references (fix: make lazy facade entry reclassification effective under rolldown-vite #269/fix: reclassify lazy facades without importers #271 behavior preserved).
  • Manifest load path: protect records by manifest key / src (the same root-relative key Vite derives), restore isEntry on a configured entry that an older build already stripped, and set isDynamicEntry on demoted facades rolldown left flagless.
  • A demotion that matches neither a configured input nor one of the plugin's own emitted chunks is reported with a warning describing the graph shape (diagnosability, per the issue).

Tests

  • Reproduced with the issue's minimal repro (packed plugin, @solidjs/web 2.0.0-rc.6, vite 8.2.2): before — isEntry=false isDynamicEntry=false dynamicImports=[self], manifest record without isEntry; after — isEntry=true, control case unchanged (decode stays its own dynamic entry).
  • Regression test in examples/css-matrix (where the fix: make lazy facade entry reclassification effective under rolldown-vite #269/fix: reclassify lazy facades without importers #271 single-entry assertion lives): the entry now statically imports the decoder next to frames/client, producing the exact self-import shape; assertions cover the raw bundle as a post-order plugin sees it (.vite/bundle-chunks.json probe), .vite/manifest.json, and the baked virtual:solid-manifest. Against the pre-fix build this fixture fails 15/49 (entry lost → no client entry CSS/asset resolution); with the fix 49/49.
  • Full gate locally: start-ssr 366/366 (+ http-bridge 10/10, components-warning 9/9), css-matrix 87/87 (+ bridge 19/19), start-client 45/45, start-env 47/47, ssr 12/12 (+ boundary 8/8), vite-8 cypress 1/1, vite-8 vitest 1/1.

normalizeEmittedLazyEntries demoted every chunk that is a dynamic-import
target, so the real client entry lost isEntry whenever it absorbed a
module that is also dynamically imported elsewhere. Solid 2 produces that
shape on its own: @solidjs/web/frames/client lazily imports the
serialization decoder, so a static import of
@solidjs/web/serialization/decode anywhere in the client graph merges the
decoder into the entry chunk and the entry lists itself under its own
dynamicImports. Downstream manifest capture (TanStack Start,
TanStack/router#8214) then failed with "No entry file found", and under
rolldown the chunk ended up neither entry nor dynamic entry because only
isEntry is synced back from generateBundle (update_output_chunk keeps the
original is_dynamic_entry).

Derive the genuine entries from the configured build input (rollupOptions
/ rolldownOptions input in any spelling, lib entry, or Vite's default
index.html — the start-mode virtual client entry included) and never
demote their facade chunks, in the raw bundle and in the manifest load
path (keyed the way Vite keys entry records, and restoring isEntry that
an older build already stripped). Ignore a chunk's dynamic import of
itself. Emitted lazy() facades are still reclassified by their emit
references; a demotion that matches neither is reported with a warning
describing the graph shape. The virtual manifest repairs isDynamicEntry
on facades rolldown left flagless.

css-matrix now builds the exact graph shape (static decoder import next
to frames/client in the entry) and asserts the bundle as a post plugin
sees it, .vite/manifest.json, and the baked virtual:solid-manifest.

Fixes #342
@changeset-bot

changeset-bot Bot commented Sep 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1f5f6ca

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

This PR includes changesets to release 1 package
Name Type
@solidjs/vite-plugin Patch

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

@pkg-pr-new

pkg-pr-new Bot commented Sep 5, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/vite-plugin@347

commit: 1f5f6ca

@ryansolid
ryansolid merged commit 668247e into next Sep 5, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant