An early look at SvelteKit

SvelteKit is a full-stack, server-side, pre-rendering application framework for Svelte that can output production builds to different environments.

An early look at SvelteKit
Selmaksan / Getty Images

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.

sveltekit demo IDG

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 at localhost: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 the Slot component. This is where the page contents will be inserted.
  • /todos: This directory contains the content that drives the localhost: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 the localhost: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 of localhost: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 the uid 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.

Copyright © 2021 IDG Communications, Inc.