Skip to content

SvelteKit

SvelteKit allows static site building, server-rendered sites, and even hybrid static-and-server-rendered web apps. It also has extremely fast hot reloading in development mode because of the way it bundles JavaScript. It adds key features like routing, layouts, and state management to Svelte.

By default, SvelteKit will render any component first on the server and send it to the client as HTML. It will then render the component again in the browser to make it interactive in a process called hydration. For this reason, you need to ensure that components can run in both places. SvelteKit will then initialize a router that takes over subsequent navigation.

Directory Structure

This is the default structure extended by best practice of myself:

static          # static content like icons
src             # source code
    lib             # reusable library files
        components      # components to build pages
        stores          # data stores
    routes          # pages and api code
    theme           # light and dark themes

docs            # documentation in markdown
site            # generated html documentation

node_modules    # libraries

build           # generated site

Routing

This is defined by the file system structure under src/routes. Two types of routes are possible here:

  1. Pages - which are *.svelte files which render HTML on the server or client.
  2. Data - which are *.js or *.ts files which mostly return JSON data for the pages.

The routes can be files or index of directory:

  • /about -> src/routes/about.svelte
  • /about -> src/routes/about/index.svelte

Dynamic parameters are encoded using [brackets]. For example, a blog post might be defined by src/routes/blog/[slug].svelte. A file or directory also can have multiple dynamic parts, like [id]-[category].svelte. (Parameters are 'non-greedy'; in an ambiguous case like x-y-z, id would be x and category would be y-z.)

Files starting with _ are hidden from the router, but can be imported by other files.

If multiple paths are matching the most specific one will be tried first, then data endpoints and then pages. The first which returns something will handle the request.

Pages

This consist of svelte templates.

Data Endpoints

Also called endpoints, will return a { status, headers, body } object representing the response, where status is an HTTP status code:

  • 2xx — successful response (default is 200)
  • 3xx — redirection (should be accompanied by a location header)
  • 4xx — client error
  • 5xx — server error

Layouts

A special page file is a layout which is called src/routes/__layout.svelte because it will automatically be used for the general layout of the pages within this directory and below. Layout will inherit from the above but you can use __layout.reset.svelte to prevent this.

Errors

If a page fails to load an __error.svelte file will be called in the specific layout.

Hooks

The file src/hooks.ts exports four functions, that run on the server:

  • handle - runs every time SvelteKit receives a request — whether that happens while the app is running, or during prerendering — and determines the response. It receives the request object and a function called resolve, which invokes SvelteKit's router and generates a response accordingly. This allows you to modify response headers or bodies, or bypass SvelteKit entirely.
  • handleError - if an error is thrown during rendering, this function will be called with the error and the request that caused it. This allows you to send data to an error tracking service, or to customize the formatting before printing the error to the console.
  • getSession - takes the request object and returns a session object that is accessible on the client and therefore must be safe to expose to users. It runs whenever SvelteKit server-renders a page.
  • externalFetch - allows you to modify a fetch request for an external resource that happens inside a load function that runs on the server.

Path Alias

To make it easier to include files from the main directories you can add specific aliases for them:

import path from 'path';

const config = {
    kit: {
        ...
        vite: {
            resolve: {
                alias: {
                    $lib: resolve('./src/lib'),
                    $components: resolve('./src/lib/components'),
                    $stores: resolve('./src/lib/stores')
                }
            }
        }
    }
};
{
    "compilerOptions": {
        ...
        "paths": {
            "$lib/*": ["src/lib/*"],
            "$components/*": ["src/lib/components/*"],
            "$stores/*": ["src/lib/stores/*"]
        }
    },
    ...
}

By default only $lib as alias to src/lib is defined. but you may shorten your includes further with the other aliases.

Modules

$app/env

import { amp, browser, dev, mode, prerendering } from "$app/env";
  • amp - is true or false depending on the corresponding value in your project configuration
  • browser - is true or false depending on whether the app is running in the browser or on the server
  • dev - is true in development mode, false in production
  • mode - is the Vite mode, which is development in dev mode or production during build unless configured otherwise in config.kit.vite.mode.
  • prerendering - is true when prerendering, false otherwise

$app/navigation

import { goto, invalidate, prefetch, prefetchRoutes } from "$app/navigation";
  • goto(href, { replaceState, noscroll, keepfocus, state }) - returns a Promise that resolves when SvelteKit navigates to the specified href. The second argument is optional:
  • replaceState (boolean, default false) If true, will replace the current history entry rather than creating a new one with pushState
  • noscroll (boolean, default false) If true, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation
  • keepfocus (boolean, default false) If true, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body
  • state (object, default {}) the state of the new/updated history entry
  • invalidate(href) - causes any load functions belonging to the currently active page to re-run if they fetch the resource in question. It returns a Promise that resolves when the page is subsequently updated.
  • prefetch(href) - programmatically prefetches the given page, which means a) ensuring that the code for the page is loaded, and b) calling the page's load function with the appropriate options. This is the same behavior that SvelteKit triggers when the user taps or mouses over an <a> element with sveltekit:prefetch. If the next navigation is to href, the values returned from load will be used, making navigation instantaneous. Returns a Promise that resolves when the prefetch is complete.
  • prefetchRoutes(routes) - programmatically prefetches the code for routes that haven't yet been fetched. Typically, you might call this to speed up subsequent navigation. If no argument is given, all routes will be fetched; otherwise, you can specify routes by any matching pathname such as /about (to match src/routes/about.svelte) or /blog/* (to match src/routes/blog/[slug].svelte). Unlike prefetch, this won't call load for individual pages. Returns a Promise that resolves when the routes have been prefetched.

$app/paths

import { base, assets } from "$app/paths";
  • base - a root-relative (i.e. begins with a /) string that matches config.kit.paths.base, or the empty string if unspecified
  • assets - an absolute URL that matches config.kit.paths.assets, if specified, otherwise equal to base

If a value for config.kit.paths.assets is specified, it will be replaced with '/\_svelte_kit_assets' during svelte-kit dev or svelte-kit preview, since the assets don't yet live at their eventual URL.

$app/stores

import { getStores, navigating, page, session } from "$app/stores";
  • getStores is a convenience function around getContext that returns { navigating, page, session }. This is needed to get them asynchronously.

The stores themselves attach to the correct context at the point of subscription. Import them at page initialization or use getStores to safely get them asynchronously instead.

  • navigating is a readable store showing current navigation like { from, to }, where from and to both mirror the page store value. When navigating finishes, its value reverts to null.
  • page is a readable store whose value reflects the object passed to load functions — it contains host, path, params and query of the current page view.
  • session is a writable store whose initial value is whatever was returned from getSession. It can be written to, but this will not cause changes to persist on the server — this is something you must implement yourself.

Own stores

Put them into src/stores and thanks to the path alias you can directly import them using $stores/xxx.

Prefetch

To speed up UI response you can add prefetch which will cause SvelteKit to run the page's load function as soon as the user hovers over the link (on a desktop) or touches it (on mobile), rather than waiting for the click event to trigger navigation. Typically, this buys us an extra couple of hundred milliseconds, which is the difference between a user interface that feels laggy, and one that feels snappy.

This can be done on a link:

<a sveltekit:prefetch href="blog/page1">First blog page</a>

You can also programmatically invoke prefetch from $app/navigation.


Last update: December 7, 2021