Thanks @three for your comment which led me to the answer.
If a route or _layout
component exports preload()
, it always gets called on navigation. So I ended up doing this by storing the fetched data in the second parameter to preload()
, which is conventionally called session
and appears to be shared among all components. And I only called this.fetch()
if the data was not already present.
<!-- blog/index.svelte -->
<script context="module">
export async function preload (page, session) {
let {posts} = session;
if (undefined === posts) {
const response = await this.fetch('blog/posts.json');
posts = await response.json();
session.posts = posts
}
return {posts}
}
</script>
<script>
export let posts;
</script>
{#each posts as post}
<!-- ... -->
{/each}
Then in [slug].svelte
check session.posts
for the post you're looking for, and if it isn't present, load it.
<!-- blog/[slug].svelte -->
<script context="module">
export async function preload (page, session) {
const {slug} = page.params
const {posts} = session
let post
if (undefined === posts) {
const response = await this.fetch(`blog/${slug}.json`)
post = await response.json()
} else {
post = posts.find(p => p.slug === slug)
}
if (undefined === post) {
this.error(404, "Sorry we couldn\'t find that post")
}
return {post}
}
</script>
<script>
export let post
</script>
<!-- ... render post -->
Now navigation is instantaneous. For ultimate robustness you could add checks to reload if the data were stale (say older than 5 minutes, whatever).
Edit
You don't actually need to be using sessions, per se. If you just want to make the session
parameter to preload(page, session)
not be undefined
you can use this in server.js
:
sapper.middleware({
// Define session parameter as an empty object
session: (req, res) => ({})
})
preload()
always gets called on navigation, regardless of whether its in_layout.svelte
, a regular page component, or both. I ended up storing the data in the second parameter topreload()
,session
, and only callingthis.fetch()
if it was empty or stale. – Sharolynsharon