SvelteKit is the successor to Sapper, the full-stack, server-side prerendering application framework for Svelte, similar to Next.js for React.
SvelteKit bears many similarities to Sapper, but adds some new and ambitious features. In particular, SvelteKit allows for targeting different production environments, including serverless environments. SvelteKit also adopts Vite as its dev-time tool, which leverages ES Modules for fast, fine-grained HMR (hot module replacement) during development.
Read on for a preview of SvelteKit, which is nearing its 1.0 release.
SvelteKit overview
The fundamental idea behind SvelteKit is to streamline the entire stack of the application into a single, standardized, file-based layout. This layout is then used to provide a consistent development experience for multiple production environments.
Let’s begin a new SvelteKit project to get a concrete sense of what this means.
On the command line, type the commands seen in Listing 1 to create a new project.
Listing 1. Starting a new SvelteKit project
npm init svelte@next test
cd test
npm install
npm run dev
You’ll see that when you run the init
command, an interactive dialog gives you the choice between the demo app and a skeleton app. Let’s use the demo app for our tour. Accept the other defaults.
When you cd
into the /test
directory and run npm run dev
, the dev server will start up and you can visit the demo app at localhost:3000
. You’ll see something like Figure 1.
Figure 1. The SvelteKit demo app.
Leave the app running. In another window, take a look at the contents of what has been created. You’ll see that a typical Node/npm-based app layout is in the root directory, including package.json
and /node_modules
.
Alongside these are some SvelteKit specifics: sveltekit.config.js
and the /src
and /static
directories.
The sveltekit.config.js
file is very short to start off, but it is where you can configure some very powerful features. The /static
directory is where static assets like images go. The heart of the application is found in /src
.
SvelteKit /src directory
Take a look inside /src
. There you will find several standard files including hooks.js
(for defining cross-cutting code that executes on every request) and app.html
(which bootstraps the front end). You don’t need to worry about those right now.
SvelteKit /src/routes directory
The centerpiece of your new app is contained in the /src/routes
directory. Open /src/routes
, and you’ll see several files and a directory. Let’s take each in turn.
about.svelte
: This is a front-end route, corresponding to the page currently hosted atlocalhost:3000/about
. This demonstrates the basic concept of file-system-based front-end routes.index.svelte
: By convention, this front-end route corresponds to the root URL,localhost:3000/
.__layout.svelte
: This is a special file that defines the shared layout to be applied to all pages. If you open it, you’ll see theSlot
component. This is where the page contents will be inserted./todos
: This directory contains the content that drives thelocalhost:3000/todos
page. Inside/todos
, you’ll find the following files:_api.js
: In SvelteKit, files prepended with the underscore character are not routes. Instead, they are used by you, the developer, as internal modules. You can see this file exports a JS module that is used elsewhere.index.svelte
: You’ve seen that this applies to an empty URL path, and it works for nested directories as well. Therefore, this file corresponds to thelocalhost:3000/todos/
page.index.json.js
: This is a back-end route. It follows the same convention as the front-end routes, and therefore provides the content oflocalhost:3000/todos.json
. If you create some todos, you’ll see the JSON output for them here. That JSON is used by the front-end routes. In short, it provides a RESTful API.[uid].json.js
: This seemingly strange syntax allows for URL path parameters. The token inside the square brackets is made available to the code in this route. In this case, the code uses theuid
variable to refer to the todo UID being worked upon.
A few general comments: First, each front-end route is defined by those routes with the .svelte
extension, and each of these pages is a Svelte component that builds that page. Second, every back-end route is a file with a .js
extension.
Front-end routes are standard Svelte components, with all the power those entail, including the ability to compose sophisticated nested component-based layouts. Back-end routes are very similar in their APIs to Express endpoints, but they are not exactly the same. Remember that SvelteKit allows you to export your app to a number of production runtimes. Node.js is just one of them.
SvelteKit adaptors
Because SvelteKit can target multiple environments, the back-end files are a kind of idealized API that can be readily transformed into actual concrete implementations within host environments.
This is accomplished via adaptors, of which there are several official adaptors and a number of community adaptors. And there’s nothing (except time and will) to prevent you building your own adaptor.
You can see that several adaptors target serverless environments like Cloudflare Workers and Vercel, and there are two “standard” adaptors for Node.js and static websites. Note that the Static adaptor means just that: It outputs a non-dynamic website.
Server-side rendering and SPAs
That summarizes the most fundamental concepts in a SvelteKit app, but it just scratches the surface of what SvelteKit is capable of. In particular, SvelteKit is a SSR (server-side rendering) framework. What that means is that the first client-side page component will (by default) be rendered on the server and delivered fully-realized to the browser. Thereafter, the pages will be loaded SPA-style (single-page app) as client-side rendered components.
This drives performance and SEO benefits (similar to Next.js), and means that your pages must be written so as to run both on the server and the client.
In practice, that means that the Svelte components must not rely on client-side-only features (like the window
object). There are ways around this, however, including the ability to detect when the page is being rendered on the browser.
Furthermore, this means that the pages can access remote APIs from both the server and the client (via the SvelteKit fetch
function, a drop-in replacement for the standard browser fetch API).
SvelteKit load() function
Finally, the isomorphic nature of SvelteKit pages means they have the superpower of pre-running data store access. This is seen in Next.js as getStaticProps
and getServerSideProps
. In SvelteKit, this access is handled via the load
function, which can be exported by pages. (SvelteKit’s load
is similar to Sapper’s preload
).
The load
function exported by pages in SvelteKit is a unique approach to handling data loading in SSR. You can think of it as a special server-side code block that provides data to the page before it is rendered. Consider the load function exported by /src/routes/todos/index.svelte
in Listing 2.
Listing 2. Todo load function
<script context="module">
import { enhance } from '$lib/form';
// see https://kit.svelte.dev/docs#loading
export const load = async ({ fetch }) => {
const res = await fetch('/todos.json');
if (res.ok) {
const todos = await res.json();
return {
props: { todos }
};
}
const { message } = await res.json();
return {
error: new Error(message)
};
};
</script>
Notice the function is provided via argument with a special fetch
function. This fetch
function has the same API as the standard one you are familiar with from the browser, but allows SvelteKit to run it on the server as well.
Notice also that the load
function returns a value. These values are automatically exposed to the page when it is rendering. In this case, that is either the set of todos or an error message, if something went awry.
A next-gen Next.js
Although SvelteKit owes a debt of inspiration to Next.js, it is definitely a next-generation framework that takes on more ambitious aims, in particular the ability to output production builds to different environments.
SvelteKit gives you all the benefits of Svelte itself, along with a multitude of end-to-end features for building dynamic, data-driven apps.