SvelteKit Tutorial
SvelteKit Tutorial
SvelteKit is a framework for rapidly developing robust, performant web applications using Svelte.
Introduction to SvelteKit
SvelteKit is a high-performance web application framework, designed around the core of Svelte. The primary goal of SvelteKit is to provide a streamlined environment for developers to rapidly create robust web applications. If you’re familiar with the React or Vue ecosystems, SvelteKit plays a role akin to Next.js or Nuxt respectively. It offers a wide range of features and functionalities that extend beyond what Svelte alone can provide.
While Svelte excels at writing user interface components, SvelteKit takes this a step further by addressing the complexities associated with constructing a complete web application.
SvelteKit Features
- Router: SvelteKit includes a router that updates the user interface as per the navigation actions taken by the user.
- Server-Side Rendering (SSR): SvelteKit supports SSR, allowing parts of your application to be rendered on the server, resulting in quicker initial page load times.
- Build Optimizations: SvelteKit incorporates best practices in building and bundling web applications, ensuring efficient code loading and offline support.
- Preloading and Configurable Rendering: It supports page preloading before the user navigates and allows you to configure which parts of your app are rendered server-side, client-side, or during build time.
- Hot Module Replacement (HMR): With SvelteKit, developers benefit from a fast and rich development experience due to HMR, which reflects code changes in the browser instantly.
Get Started with SvelteKit
Use npm to create a new SvelteKit application
npm create svelte@latest my-app
cd my-app
npm install
npm run dev
This command scaffolds a new project in the my-app directory with optional basic tooling like TypeScript (make sure to choose your desired stack), installs dependencies, and starts a server on localhost:5173.
The basics:
- Each page in your application is a Svelte component.
- You create pages by adding files to the src/routes directory. These files are server-rendered initially for faster page loads, and a client-side app takes over subsequently.
- Server-side rendering may not be compatible with libraries that use window or other browser-specific APIs. Use client-side rendering or dynamic imports for these libraries.
- Ensure your editor has a Svelte extension for proper syntax highlighting and error reporting.
SvelteKit Project Structure
The SvelteKit project structure is familiar if you’ve worked with modern front-end frameworks like Next.js or Nuxt.js, with a few unique concepts to grasp.
Typical Project Structure
A standard SvelteKit project contains the following structure:
my-project/
├ src/
│ ├ lib/
│ │ ├ server/
│ │ │ └ [your server-only lib files]
│ │ └ [your lib files]
│ ├ params/
│ │ └ [your param matchers]
│ ├ routes/
│ │ └ [your routes]
│ ├ app.html
│ ├ error.html
│ ├ hooks.client.js
│ └ hooks.server.js
├ static/
│ └ [your static assets]
├ tests/
│ └ [your tests]
├ package.json
├ svelte.config.js
├ tsconfig.json
└ vite.config.js
Key Files and Directories
src/: The main application source directory. Essential files and directories includeroutes/for routing, andapp.html, the page template.lib/: Contains utility functions and components. It’s divided into general and server-only code (server/). You can import via$liband$lib/serveraliases respectively.params/: Hosts any parameter matchers your application needs for advanced routing.routes/: Stores route files for your application. Route-related components can also be colocated here.app.html: The application template. It includes placeholders for head elements (%sveltekit.head%), the rendered page markup (%sveltekit.body%), path to assets (%sveltekit.assets%), a CSP nonce if used (%sveltekit.nonce%), and render-time environment variables (%sveltekit.env.[NAME]%).error.html: Serves as the fallback page in case of failures, with placeholders for HTTP status (%sveltekit.status%) and error message (%sveltekit.error.message%).hooks.client.jsandhooks.server.js: These files contain client and server hooks respectively.
static/: Holds static assets likerobots.txtorfavicon.png, which are served as-is.tests/: Contains your tests, using Playwright for browser testing if added during setup.package.json: Includes@sveltejs/kit,svelteandviteas devDependencies.svelte.config.js: Contains your Svelte and SvelteKit configuration.tsconfig.jsonorjsconfig.json: Configures TypeScript, if type checking was added during project setup.vite.config.js: A SvelteKit project is essentially a Vite project that uses the@sveltejs/kit/viteplugin, along with any other Vite configuration.
Special Features SvelteKit introduces new concepts, which aren’t common in other frameworks:
lib/andparams/directories for server-side code and parameter matching respectively.- Use of
%sveltekit.head%,%sveltekit.body%,%sveltekit.assets%,%sveltekit.nonce%, and%sveltekit.env.[NAME]%placeholders inapp.html. - Different client and server-side hooks located in
hooks.client.jsandhooks.server.js. - The inclusion of Vite in the framework, using
vite.config.js.
Gotchas:
- Server-only code in
lib/server/should be used carefully, as trying to import it into client-side code will raise errors. app.htmlrequires special attention due to the placeholder mechanism, especially%sveltekit.body%, which should reside within a<div>or similar element to prevent issues related to browser extensions.
SvelteKit and Web APIs
SvelteKit takes advantage of several standard Web APIs, making it easier for developers familiar with modern web development to use SvelteKit. Time spent learning SvelteKit will also enhance your web development skills.
The Web APIs used by SvelteKit are supported in all modern browsers and in many non-browser environments like Cloudflare Workers, Deno, and Vercel Edge Functions. They’re also polyfilled where necessary during development and in adapters for Node-based environments.
Here are some key Web APIs that SvelteKit makes use of:
1. Fetch API
-
Fetch: SvelteKit uses the Fetch API to get data from the network. A special version of fetch is also available in load functions, server hooks, and API routes, allowing server-side rendering to invoke endpoints directly without making an HTTP call.
-
Request: An instance of Request is accessible in hooks and server routes as
event.request. This contains useful methods for getting data that was posted to an endpoint. -
Response: An instance of Response is returned from
await fetch(...)and handlers in+server.jsfiles. This forms the basis of a SvelteKit app, converting a Request into a Response. -
Headers: This interface allows you to read incoming
request.headersand set outgoingresponse.headers.
2. FormData API
The FormData API is used when dealing with HTML native form submissions, creating FormData objects.
3. Stream APIs
SvelteKit uses streams when you need to return a response that’s too large to fit in memory in one go or is delivered in chunks. This includes ReadableStream, WritableStream, and TransformStream.
4. URL APIs
URLs are represented by the URL interface, which shows up in several places, including event.url in hooks and server routes, $page.url in pages, from and to in beforeNavigate and afterNavigate.
- URLSearchParams: This allows you to access query parameters via
url.searchParams.
5. Web Crypto API
The Web Crypto API is used for tasks like generating UUIDs. It’s available via the crypto global.
Gotchas:
-
Be mindful of browser compatibility when using these APIs. While SvelteKit provides polyfills during development, it’s still essential to test your application on all target browsers.
-
For server-side rendering, the fetch function in load functions and server hooks allows you to invoke endpoints directly, but be aware that you need to pass
cookieand/orauthorizationheaders explicitly for credentialled fetches. -
Working with streams can be complex due to their asynchronous nature. It’s recommended to use libraries that provide higher-level abstractions for streams when working with large data.
-
Be careful when reading incoming request headers and setting outgoing response headers. Always sanitize and validate headers to prevent potential security issues.
-
When using the Web Crypto API, be aware that not all of its features are available in all environments. Some functions may not be available in older or less-common browsers.
Core Concepts
Routing
Svelte’s Routing system is based on the structure of your codebase, specifically the directories, forming a filesystem-based router. The root route is designated by the directory src/routes, and you can create additional routes by adding more directories, like src/routes/about for an /about route.
Svelte uses a special system for its routes, called route files, recognizable by a + prefix. Each route directory contains one or more of these files.
A +page.svelte file represents a page in your app. Pages are server-rendered by default for the initial request and browser-rendered for subsequent navigation. These components can include any HTML structure and interactive components.
To load data before rendering, +page.js files are used, exporting a load function. This function runs on the server during server-side rendering (SSR) and in the browser during client-side rendering (CSR).
There are options to configure the page’s behavior in +page.js such as prerender, SSR, and CSR configurations.
When a load function must only run on the server, for instance when fetching data from a database or accessing private environment variables, +page.js can be renamed to +page.server.js.
Svelte also provides a way to handle errors during the load process by providing an +error.svelte file. This file customizes the error page on a per-route basis.
Moreover, Svelte supports layouts which are elements visible on every page, like a navigation bar or a footer. These are implemented through +layout.svelte files. Layouts can be nested to accommodate more complex page structures.
+layout.js is the data loading equivalent for layouts, similar to +page.js for pages.
API routes or endpoints are defined using a +server.js file, giving you full control over the response. They correspond to HTTP verbs like GET, POST, PATCH, PUT, DELETE, and OPTIONS and return a Response object.
In summary, Svelte’s Routing system is a dynamic, file-based system where the file and directory structure dictates the routes of your application. The router supports error handling, layouts, and server responses, making it highly flexible for different application needs.
Routing Example
src/routes/+page.svelte
<h1>Hello and welcome to my site!</h1>
<a href="/about">About my site</a>
src/routes/about/+page.svelte
<h1>About this site</h1>
<p>TODO...</p>
<a href="/">Home</a>
src/routes/blog/[slug]/+page.svelte
<script>
/** @type {import('./$types').PageData} */
export let data;
</script>
<h1>{data.title}</h1>
<div>{@html data.content}</div>
src/routes/blog/[slug]/+page.js - load data before rendering
import { error } from '@sveltejs/kit';
/** @type {import('./$types').PageLoad} */
export function load({ params }) {
if (params.slug === 'hello-world') {
return {
title: 'Hello world!',
content: 'Welcome to our blog. Lorem ipsum dolor sit amet...'
};
}
throw error(404, 'Not found');
}
+page.server.js - only runs on server
import { error } from '@sveltejs/kit';
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
const post = await getPostFromDatabase(params.slug);
if (post) {
return post;
}
throw error(404, 'Not found');
}