Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$layout unexpectedly initialises twice in development #1214

Closed
intrikate opened this issue Apr 25, 2021 · 17 comments
Closed

$layout unexpectedly initialises twice in development #1214

intrikate opened this issue Apr 25, 2021 · 17 comments

Comments

@intrikate
Copy link

Describe the bug
Updating $layout.svelte and reloading the page makes it initialise and mount twice: once on reload and once more on next navigation. This will repeat on every page reload until the dev server is restarted.

To Reproduce

  • Clone and run: https://github.com/intrikate/sveltekit-layout-init-issue.
  • Navigate to localhost:3000, open the console.
  • Update src/routes/$layout.svelte in any way (e.g. delete the empty comment in line 4).
  • Save and reload the page. (HMR on its own does not trigger this behaviour.)
  • Use the links for navigation, count the console statements about the layout lifecycle.

Expected behavior
The layout component should mount once and persist between routes, with no unmounts and reinitialisation.

Information about your SvelteKit Installation:

Diagnostics

System:
OS: macOS 11.2.3
CPU: (4) x64 Intel(R) Core(TM) i5-4288U CPU @ 2.60GHz
Memory: 55.59 MB / 8.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 14.16.0 - /usr/local/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 6.14.11 - /usr/local/bin/npm
Browsers:
Chrome: 90.0.4430.85
Firefox Developer Edition: 89.0
Safari: 14.0.3
npmPackages:
@sveltejs/kit: next => 1.0.0-next.89
svelte: ^3.37.0 => 3.37.0
vite: ^2.2.2 => 2.2.2

Severity
High, as it leads to obscure lifecycle-related bugs.

Additional Context
Complex transitions and per-route layout tweaks are difficult or outright impossible without the layout to coordinate them.

@UltraCakeBakery
Copy link

I've been experiencing this behavior since .83. It looks like a route navigation is required for hydration to actually effect the dom. As if the hydration the first time doesn't complete itself right before it is supposed to update the DOM and doesn't remember that it already did something.

@UltraCakeBakery
Copy link

UltraCakeBakery commented Apr 26, 2021

I also now have my components inside my $layout being added to the DOM twice. Once inside my layout where they are supposed to mount (as specified in my code) and outside my hydration target.

edit: will setup a repo for this if the behavior doesn't disappear in the next few updates

@intrikate
Copy link
Author

I've been experiencing this behavior since .83.

I can still reproduce it in .82. Apparently, the most recent one where I can’t is .71.

I was actually thinking of commenting on #1171, but opted to reduce it further and specify triggering conditions (wasn’t sure those matched between the two). Overall, #1171 is pretty similar to the real case where it first bit me. Add stores to the mix (as, say, in the proposed solution to your #1110), throw in store-triggered transitions, and you’re a queen bee.

@chuckrector
Copy link

I've been porting a Sapper app over to SvelteKit and have been experiencing something similar. It may be a separate issue but it does share the duplication aspect. Here is a minimal repro: https://github.com/chuckrector/kit-dupes

I had copy/pasted a large Sapper component over into my SvelteKit project and noticed that only a certain part of it was getting duplicated on reload. I whittled the entire file down to this:

SvelteKit <a href="/"><a href="/">test</a></a>

The repro linked above was created by following the instructions on the landing page, as a fresh SvelteKit skeleton project with no other frills and replaces index.svelte with the above content. There is no $layout.svelte. It seems to happen in both development mode and in preview mode.

@intrikate
Copy link
Author

@chuckrector How long have you been having this? Nested anchors are tricky, as would be any invalid HTML, but otherwise it looks pretty much like #1288.

@chuckrector
Copy link

@intrikate I started yesterday after Rich retweeted some of the new changes in 3.38. The issue you've linked appears to be precisely it. Thank you! Having read that it was resolved, I tried creating a new SvelteKit project with the latest changes and can no longer reproduce the issue. Li Hau is quick on his feet. 🏃‍♂️💨

@asv7c2
Copy link

asv7c2 commented May 2, 2021

@intrikate
Looks like bug is fixed now.

@intrikate
Copy link
Author

intrikate commented May 2, 2021

@asv7c2, are you’re referring to sveltejs/svelte#6274 (formerly #1288)? This one isn’t actually related and still reproducible with .94 and Svelte 3.38.1; they just happen to both be triggered by hydration.

@asv7c2
Copy link

asv7c2 commented May 2, 2021

@intrikate
No, i checked your repo, layout is mounted only once.

@intrikate
Copy link
Author

@asv7c2, now that’s strange, I can still see it. You did update the file, right?

@asv7c2
Copy link

asv7c2 commented May 2, 2021

@intrikate
Sorry, bug is here. I just not editing $layout.

@Litarvan
Copy link

Litarvan commented May 2, 2021

I'm having the same issue, this prevents my css transitions in the layout to happen between route changes (as the layout component is re-initialized).

@intrikate
Copy link
Author

intrikate commented May 4, 2021

I believe we’re looking at misplaced layout reset. In short, once the $layout is modified in any way, the component passed for hydration and the one loaded with the next route are no longer identical, even though they are obviously the same layout. Failing the identity check, the old layout is destroyed and replaced by the new one. None of this behaviour is unexpected, except for the two imports of a single module failing the ===.

Turns out, updating layouts compromises the manifest as the source of truth, because the relevant dependency is now /src/routes/$layout.svelte on the server, but /src/routes/$layout.svelte?t=TIMESTAMP on the client. Prerendered and inlined, the start call relies on the server view of things, importing components that perfectly satisfy hydration, but won’t survive the next route load.

The simplest solution is to externalise component imports; as long as they’re not inlined, they receive timestamps like everything else and don’t offend the renderer. I’m not currently happy with the implementation I have in mind, so suggestions are welcome.

@wiesson
Copy link
Contributor

wiesson commented May 10, 2021

I'm experiencing some similar issues and I'm wondering if they are related.

My flow:

  1. /auth/signup/profile (__layout.reset.svelte), checks in onMount if user is not authenticated, goto("/auth/login")
  2. /auth/login -> logs in, goto("/auth/signup/profile")
  3. /auth/signup/profile - onMount is not called again

From your description, I just guess that goto() leaves the page too early so that hydration or some other processes can't finish. I also saw duplicated pages on top of each other (old on on top, new one bellow) - and as always happened only in prod, not in dev 😅

@intrikate
Copy link
Author

Shouldn’t be related, no. This one is dev-specific, I’d be surprised to see it in prod. It also shouldn’t cause duplication – excess mounts are evened out by excess unmounts.

If I understand your description correctly, you’re receiving fewer onMount calls than expected. If so, you may be hitting a separate issue.

@wiesson
Copy link
Contributor

wiesson commented May 11, 2021

Thanks @intrikate - I will try to reproduce it and create a separate issue

@benmccann
Copy link
Member

Closing as duplicate of #2130

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

No branches or pull requests

7 participants