This repository was archived by the owner on Jan 11, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 428
Use slots for routing #573
Comments
My best attempt at figuring out what the generated component would look like so far: <script>
import Layout from '../../../routes/_layout.svelte';
import Error from '../../../routes/_error.svelte';
export let error;
export let level0;
export let level1;
export let level2;
</script>
<Layout segment={level0.segment} {...level0.data}>
{#if error}
<Error {...error}/>
{:else}
<svelte:component this={level1.component} segment={level1.segment} {...level1.data}>
{#if level2}
<svelte:component this={level2.component} {...level2.data}/>
{/if}
</svelte:component>
{/if}
</Layout> This is for an app with a) a root <script>
import Error from '../../../routes/_error.svelte';
export let error;
export let level0;
export let level1;
</script>
{#if error}
<Error {...error}/>
{:else}
<svelte:component this={level0.component} segment={level0.segment} {...level0.data}>
{#if level1}
<svelte:component this={level1.component} {...level1.data}/>
{/if}
</svelte:component>
{/if} Conversely, if it had one or more routes with two intermediate layout components (probably unusual, but there's no limit to the number of layout components you can have) then it'd look like this: <script>
import Layout from '../../../routes/_layout.svelte';
import Error from '../../../routes/_error.svelte';
export let error;
export let level0;
export let level1;
export let level2;
</script>
<Layout segment={level0.segment} {...level0.data}>
{#if error}
<Error {...error}/>
{:else}
<svelte:component this={level1.component} segment={level1.segment} {...level1.data}>
{#if level2}
<svelte:component this={level2.component} {...level2.data}>
{#if level3}
<svelte:component this={level3.component} {...level3.data}/>
{/if}
</svelte:component>
{/if}
</svelte:component>
{/if}
</Layout> Upon navigation, Sapper would do something like this pseudo-code: const data = {};
await Promise.all(route.levels.map(async (level, i) => {
if (changed(level, i)) {
const mod = await level.load();
data[`level${i}`] = {
segment: segments[i + 1],
component: mod.default,
data: mod.preload ? await mod.preload(...) : {}
};
}
});
app.$set(data); |
Merged
Rich-Harris
added a commit
that referenced
this issue
Feb 21, 2019
Implemented some time ago in #574. |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
This is a bit of an existential mega-issue for Sapper. Will try and articulate what's in my head as succinctly as possible. (It mostly concerns internal implementation details, and would only entail minor changes to Sapper apps themselves.)
At present, nested routing is handled with
_layout.svelte
components that have to contain something like the following:Upon navigation, Sapper constructs a new tree for the current route, which looks something like this (assuming the user was visiting
/foo/bar
):That data is passed to the root component, and the app redraws. If you were to navigate from
/foo/bar
to/foo/baz
,props.child.component
andsomePreloadedData
would stay as they are, which is nice, and ifSomeLeafComponent
is used for bothbar
andbaz
, we only need to re-run that component'spreload
function to get new data for the leaf. So in terms of preserving the component tree and minimising the amount ofpreload
data-fetching etc, it's quite efficient.But. Because we're applying that data at the top level, we're still setting
props.child.props
on the layout component, which can cause (avoidable, but surprising) side-effects, due to the component thinking it has received new state.Then there's the
child
value itself, which is a Sapperism that components have to accommodate (by declaringexport let child
, etc). And it's a bit weird that we're using<svelte:component>
for something that<slot>
is conceptually better suited to.What if we used
<slot>
instead?Component-based routing
There are basically three different approaches to routing:
The advantage of fs-based routing is that you get code-splitting for free (because the framework does the complicated part for you — it's able to do so because your routes are essentially statically analysable), along with a pretty nice development experience. But if we had component-based routing, we could avoid the inefficiency outlined above:
Here, if
someMorePreloadedData
changes (as a result of a navigation from/foo/bar
to/foo/baz
), we needn't touch<SomeLayoutComponent>
at all.(In this case,
<SomeLayoutComponent>
contains<slot>
instead of<svelte:component>
.)Of course, we don't have code-splitting any more. We'd need to jump through some additional hoops. And I don't want to build my apps that way, I want to use filesystem-based routing. But we can make Sapper write that stuff for us. I haven't figured out exactly what it looks like, but it feels like a promising avenue of investigation.
Bonus thoughts
@sveltejs/router
package?The text was updated successfully, but these errors were encountered: