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

Dynamic components removed during hydration #13

Closed
jimafisk opened this issue Oct 19, 2020 · 5 comments
Closed

Dynamic components removed during hydration #13

jimafisk opened this issue Oct 19, 2020 · 5 comments

Comments

@jimafisk
Copy link

Hi @lukeed,

In my project there's a bug where dynamic components (<svelte:component this={route}>) are temporarily removed during hydration on initial page load. This results in a cumulative layout shift that looks like a flash of content to the user. You can see an example of it on the website for the project: https://plenti.co/

Also, here are some screenshots from the default starter of the project:

Screenshot during hydration

pmissing

Screenshot after being fully loaded

pfull

I initially thought this might be a known hydration issue with svelte, and even opened an issue to confirm that. However, I tried replicating hydrating dynamic components without the router and it seems to work correctly: https://github.com/jimafisk/svelte-dynamic-components

Then I pulled down the Svelte demo for Navaid (https://github.com/lukeed/svelte-demo) and noticed the same issue. Here are some screenshots:

Screenshot during hydration

missing

Screenshot after being fully loaded

full

I'm curious if maybe the Route isn't getting set to a class constructor in time during the hydration process. Do you happen to know what might be going on here? Thanks again for all the help, and great presentation at svelte-summit today :).

@lukeed
Copy link
Owner

lukeed commented Oct 19, 2020

Hey, it's not a bug actually. It makes sense if you think about what's going on:

  • Client loads
  • Navaid starts
  • App.svelte is given undefined Route prop
  • Navaid matches route
  • Page route loaded via import()
  • App.svelte is given 1st Route value

Until the last step is reached, the Svelte app is told nothing is supposed to be on the page. This means that if you had SSR content there, Svelte clears it.

Because my svelte-demo isn't SSR'd, the approach provided is fine. There's nothing by default, which means nothing gets cleared.

However, in the SSR case, you have to defer that first "draw" until the first import resolves. In svelte world, that means waiting to do app = new App(...) until that import is finished -- and at that point you'll have a Route property too.

Lemme know if that helps! Happy to send over code sample tomorrow.

PS, Plenti looks awesome & I appreciated the shout-out 🙌 Looking forward to trying it out!

@jimafisk
Copy link
Author

Thanks for the quick response @lukeed! I appreciate you breaking down the steps, that helps me understand what's happening conceptually. I think you've diagnosed the issue exactly right, I'm just still having a little trouble figuring out how to implement deferring the draw correctly. If you're able to send a code snippet without too much trouble, I'd really appreciate it! Thank you!

@lukeed lukeed transferred this issue from lukeed/navaid Oct 19, 2020
@lukeed
Copy link
Owner

lukeed commented Oct 19, 2020

Hey, I moved the issue here since it's more relevant to this repo – and as discussed, it's not a Navaid bug :D

Here's an example branch on this repo, showing how to defer hydration until the first import resolves: 410388e

This is the typical setup I have (and what I also set up automatically within new freshie apps). Routing is controlled by the boot script. And with Svelte specifically, this allows you to move/separate routing logic from the Svelte app itself, which in turn allows your server to pass in the necessary prop values to render desired content.

So, for example, you can do something like this on the server:

import App from './App.js'; // built output
import * as About from './About.js'; // built output

async function render(req, Component) {
	let props = {
		params: req.params,
		Route: Component.default,
		pathname: req.path,
		// ...
	};

	if (Component.preload) {
		Object.assign(props, await Component.preload(req));
	}

	const output = App.render(props);

	// ...
}

//=> render(req, About)

@jimafisk
Copy link
Author

Thanks for all the examples @lukeed! I was toying with something similar, but this really helped clarify things for me. I have a working model now: plentico/plenti@1eccf04 (Just need to fix an unrelated issue). I appreciate you taking the time to break things down and point me in the right direction!

@lukeed
Copy link
Owner

lukeed commented Oct 20, 2020

Not a problem, glad I could help!

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

2 participants