Introduction
It’s been around a month since SvelteKit v1 was released and I fortunately got enough time to play around with it. In this blog post, I would be writing about the data fetching/loading ways in SvelteKit and how SvelteKit makes it easier along with providing type-safety all the way!
Creating a new SvelteKit app
Let’s start from the basics in case you know nothing about Svelte. I’ll be creating a new SvelteKit app first. You can use this command to do it as well (make sure you opt-in to use typescript when prompted) -
pnpm create svelte@latest // or npm create svelte@latest
Now that we have our project setup, let’s build a new page. SvelteKit uses a file-based routing just like other frameworks like Next.js. Head over to src/routes/+page.svelte
in your app. This is the starting point of any SvelteKit app - the Index page. I won’t be creating any more routes as we don’t need them for this blog post. You can learn more about routing from SvelteKit docs. Start the dev server for the app and if you did everything correctly you should be seeing a page like this if you head over to localhost:5173.
Understanding data loading in SvelteKit
Now let’s start with the actual topic of this blog post - data fetching. If you read the SvelteKit docs for data fetching, it states that you need separate files for loading your data which can be created for every route - “A +page.svelte
file can have a sibling +page.js
(or +page.ts
) that exports a load
function, the return value of which is available to the page via the data
prop”. Didn’t get it? don’t worry, let’s break it into parts.
So, first of all for every route that you want to load/fetch external data, you need a separate file. For example, for every +page.svelte
in your routes where you need external data, you will need a corresponding +page.ts
file for loading its data. The second part says something about a load
function. A load function is the function that you export from your +page.ts
file returning the loaded data. SvelteKit autogenerates the return types for you which can be imported in your component file using $types
module. I think it might be making some sense at this point, but let’s see this in action.
Do it yourself
Let’s create a new route todo
in our app and create +page.svelte
and +page.ts
files inside it. I’ll be using dummyjson to mimic an external database.
// src/routes/todo/+page.ts
import type { PageLoad } from './$types';
type todo = {
id: number;
todo: string;
completed: boolean;
userId: number;
}; // todo type for better type safety
type t = {
todos: todo[];
total: number;
skip: number;
limit: number;
}; // actual json reponse type
export const load: PageLoad = async () => {
const r = await fetch('https://dummyjson.com/todos');
const todos = ((await r.json()) as t).todos; // we only want to send the todo array as props
return {
props: {
todos
}
};
};
<!-- src/routes/todo/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
</script>
<h1>Todo List</h1>
{#each data.props.todos as todo (todo.id)}
<div>
<p>{todo.todo}</p>
</div>
{/each}
If you copy this code to your editor, you would be able to see some beautiful typescript autocompletion working in here. Let’s try to understand the code.
Understanding the code
First of all I created a +page.ts
file inside my todo
route and created a load
function of the type PageLoad
. I have fetched the json response from dummyjson inside the function and returned an array of todos from the response. The type t
at the beginning is optional and you may not use it but the type todo
is important if you want end-to-end type-safety (also it’s a good practice to keep all the types in a separate file and import them, instead of cluttering the main file).
SvelteKit then generates the types for the load
function which could be used in our +page.svelte
. In the src/routes/todo/+page.svelte
, we first need to import the generated types and then export it as data
. The next part is pretty easy if you already know Svelte syntax, we just need to iterated over the array of list and list them down.
If you do everything correctly and then head over to localhost:5173/todo, you would be able to see something like this -
Fetching data server side
So, our data fetching works perfectly fine. You could experiment a bit more with it if you want. But I’ll head over to the last subtopic of the blog which is loading data server side only. In many cases, you would not want your load
function to not run client side (because it uses private environment variables, for example, or accesses a database). For such cases, SvelteKit provides another similar way for loading data.
To do so, instead of creating a +page.ts
, you’ll just have to create a +page.server.ts
and change the function type a bit like this -
// src/routes/todo/+page.server.ts
import type { PageServerLoad } from './$types';
type todo = {
id: number;
todo: string;
completed: boolean;
userId: number;
}; // todo type for better type safety
type t = {
todos: todo[];
total: number;
skip: number;
limit: number;
}; // actual json reponse type
export const load: PageServerLoad = async () => {
const r = await fetch('https://dummyjson.com/todos');
const todos = ((await r.json()) as t).todos; // we only want to send the todo array as props
return {
props: {
todos
}
};
};
Conclusion
You can learn more about the PageLoad
and PageServerLoad
types from the docs. If you are new to Svelte and SvelteKit, this might have been a bit harder to understand (maybe) or maybe even some of you wouldn’t like this way of loading data (why do we need to create separate files????). But, believe me, once you start using it, it just becomes natural as your app just gets more organized and I don’t think it’s that bad considering the type-safety you get along with it without using any third party library.
This is it for this blog post, I hope I was able to explain the topic properly. In case you don’t understand something or think something’s not right, feel free to send a comment my way!
Thanks a lot for reading!
Top comments (2)
Good one Chief💪🏾.
You and @nexxeln really inspire me.
❤