sveltejs / svelte · Issue No. 18554
With compilerOptions.experimental.async: true, replacing two nested dynamic components in one synchronous $state assignment instantiates the new leaf component twice. Its onMount runs twice, and one of the instances is transient, torn down right after mounting while still reactively alive (in a larger app this also surfaces as derived_inert warnings). There are no await expressions anywhere in the repro.
Three conditions are required together, removing any one of them gives a single mount:
children through that ancestor.<Component>s (two levels, the new leaf is the one that doubles). A static {#if} swap of the same components mounts once.With experimental.async: false everything mounts once.
Extracted from sveltejs/kit#16166. It reproduces without SvelteKit (repro below is plain Vite + Svelte), so it is not a kit bug. Kit is the natural trigger because its client swaps the route component tree exactly like this on every navigation, and the snippet-teleport pattern is the standard workaround for sveltejs/kit#627.
https://github.com/Nic-Polumeyv/svelte-async-double-mount
npm install && npm run dev
Click navigate. The on-page verdict and console show nested/page mounting twice. The README has the full ablation table.
[mount] nested/page
[mount] nested/layout
DOUBLE MOUNT: nested/page mounted 2x
svelte: 5.56.6
@sveltejs/vite-plugin-svelte: 7.1.2
vite: 8.0.16
node: 22.23.1 (linux)
Also reproduces through SvelteKit on macOS per the original kit report (kit 3.0.0-next.4 and next.8).
annoyance
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.