DEV Community

Tianya School
Tianya School

Posted on

SvelteKit A New Framework for Building High-Performance SSR Applications

SvelteKit is a next-generation framework based on Svelte, designed for building server-side rendered (SSR) and static site generated (SSG) applications. Svelte is a lightweight frontend framework known for its exceptional performance and concise code. SvelteKit extends Svelte’s capabilities, providing a complete development workflow, including routing, data fetching, API calls, and server-side rendering.

Svelte Components

SvelteKit applications are built on Svelte components, which are reusable UI blocks. A typical Svelte component includes three main sections:

  • <script> tag: Defines component state, logic, and module imports.
  • <style> tag: Specifies private styles scoped to the component, preventing leakage to other components.
  • HTML or Svelte syntax: Defines the component’s template, determining what is rendered.

Here’s an example of a simple Svelte component, Hello.svelte:

<script>
  // Define component state
  let name = 'World';

  // Export variables as component props
  export let greeting = 'Hello';
</script>

<!-- HTML/Svelte template -->
<h1>{greeting}, {name}!</h1>

<style>
  /* Private component styles */
  h1 {
    color: blue;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Reactive Variables

In the <script> tag, variables are reactive by default. Svelte automatically tracks changes and updates the view when they occur. In the example above, name and greeting are reactive.

Exported Props

Using the export keyword, variables can be exposed as component props, allowing parent components to pass values. In the example, greeting is an exportable prop.

Computed Properties and Methods

Svelte supports computed properties and methods in the <script> tag, calculated based on reactive variables:

<script>
  let count = 0;
  $: doubledCount = count * 2;

  function increment() {
    count += 1;
  }
</script>

<button on:click={increment}>{count} or {doubledCount}</button>
Enter fullscreen mode Exit fullscreen mode

Conditional Rendering and Loops

Svelte supports conditional rendering (if and else) and loops (each) for dynamic content:

{#if showing}
  <p>Visible content</p>
{:else}
  <p>Hidden content</p>
{/if}

{#each items as item}
  <div>{item.name}</div>
{/each}
Enter fullscreen mode Exit fullscreen mode

Event Handling

Svelte uses the on: prefix to listen for and handle DOM events:

<button on:click={handleClick}>Click me</button>
Enter fullscreen mode Exit fullscreen mode

Custom Directives

Svelte provides custom directives like bind: and use: to extend component behavior. For example, bind: enables two-way binding:

<input bind:value={name} />
Enter fullscreen mode Exit fullscreen mode

Lifecycle Hooks

Svelte offers lifecycle functions like onMount, beforeUpdate, and onDestroy for executing code at specific component stages:

<script>
  import { onMount, onDestroy } from 'svelte';

  let mounted = false;

  onMount(() => {
    console.log('Component has been mounted');
    mounted = true;
  });

  function cleanup() {
    console.log('Component is being destroyed');
  }

  onDestroy(cleanup);
</script>
Enter fullscreen mode Exit fullscreen mode

Routing

1. Routing Structure

SvelteKit’s routing is tightly coupled with the file system in the src/routes directory. Each directory or file corresponds to a route:

  • src/routes/index.svelte: The app’s homepage.
  • src/routes/blog/[slug].svelte: A blog post page, where [slug] is a dynamic parameter.

2. Static Routes

Static routes map fixed URLs to Svelte components. For example, src/routes/about.svelte matches the /about path.

3. Dynamic Routes

Dynamic routes capture URL segments as parameters, denoted by square brackets (e.g., [id]). In the blog example, [slug] captures strings like /blog/my-first-post, passing my-first-post as the slug parameter.

Load Function

Each route component can define a load function to fetch data on the server or client, returning a Promise whose result becomes component props:

<script context="module">
  export async function load({ params }) {
    const response = await fetch(`/api/posts/${params.slug}`);
    const post = await response.json();
    return { props: { post } };
  }
</script>

<script>
  export let post;
</script>

<h1>{post.title}</h1>
<p>{post.content}</p>
Enter fullscreen mode Exit fullscreen mode

4. API Routes

SvelteKit supports API endpoints by creating .js or .ts files in src/routes instead of .svelte files. For example, src/routes/api/posts.js handles requests to /api/posts:

export async function get({ params }) {
  const response = await fetch(`https://api.example.com/posts/${params.id}`);
  return {
    body: await response.json(),
  };
}
Enter fullscreen mode Exit fullscreen mode

5. Middleware

SvelteKit allows middleware files, like _middleware.js in src/routes, to handle all route requests for tasks like authentication or logging:

export async function handle({ request, resolve }) {
  const token = request.headers.get('Authorization');

  if (validateToken(token)) {
    return resolve(request);
  } else {
    throw new Error('Unauthorized');
  }
}
Enter fullscreen mode Exit fullscreen mode

6. Route Navigation

Use the goto function for client-side navigation or apply the use:link action to <a> tags:

<script>
  import { goto } from '$app/navigation';
</script>

<button on:click={() => goto('/about')}>
  Go to About Page
</button>

<a href="/about" use:link>Go to About Page</a>
Enter fullscreen mode Exit fullscreen mode

7. Route Parameters and Query Strings

Pass route parameters and query strings with goto:

<script>
  import { goto } from '$app/navigation';
</script>

<button on:click={() => goto('/blog/some-post', { id: 123 })}>
  View Post
</button>
Enter fullscreen mode Exit fullscreen mode

Data Fetching

SvelteKit provides a flexible data-fetching mechanism via the load function, used during SSR, client initialization, and navigation.

1. Load Function

The load function runs when a page loads, fetching data and returning props for the component:

<script context="module">
  export async function load({ page, session }) {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return { props: { data } };
  }
</script>

<script>
  export let data;
</script>

<ul>
  {#each data as item}
    <li>{item.name}</li>
  {/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

2. Load Function Parameters

  • page: Contains route information, like page.params (dynamic route parameters) and page.query (query string parameters).
  • session: Stores user session data, useful for authentication.

3. Separating Client and Server Logic

The load function can differentiate between client and server logic:

<script context="module">
  export async function load({ page, session }) {
    let data;

    if (import.meta.env.SSR) {
      // Server-side logic
    } else {
      // Client-side logic
    }

    return { props: { data } };
  }
</script>
Enter fullscreen mode Exit fullscreen mode

4. Caching and Redirects

The load function can return status, headers, and redirect properties to control HTTP responses:

<script context="module">
  export async function load({ page }) {
    const response = await fetch('https://api.example.com/data');
    if (response.status === 401) {
      return {
        status: 401,
        redirect: '/login',
      };
    }

    const data = await response.json();
    return { props: { data } };
  }
</script>
Enter fullscreen mode Exit fullscreen mode

5. Client-Side Data Updates

The load function can rerun during navigation or component updates to refresh data, using the page.changed property:

<script context="module">
  export async function load({ page }) {
    if (page.changed.query) {
      // Query string changed, refetch data
    }
    // ...
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Server-Side Rendering (SSR)

SvelteKit supports SSR by default, rendering full HTML on initial load for better SEO and faster first-paint times. The load function executes server-side, and the fetched data is rendered into HTML.

Static Site Generation (SSG)

SvelteKit supports SSG for prerendering static HTML pages. Running svelte-kit build in production generates a static site deployable to any static hosting service.

API Routes

Beyond page routes, SvelteKit supports API routes via .js or .ts files in src/routes. For example, src/routes/api/data.js handles /api/data requests:

export async function get(request) {
  const response = await fetch('https://api.example.com/data');
  return {
    body: await response.json(),
  };
}
Enter fullscreen mode Exit fullscreen mode

Authentication and Middleware

Reusable middleware can be written in the src/lib directory, running at different stages of the request lifecycle. For example, an authentication middleware:

// src/lib/auth.js
export function authenticate(req, res, next) {
  const token = req.headers.authorization || '';
  if (validateToken(token)) {
    next();
  } else {
    res.status(401).end();
  }
}
Enter fullscreen mode Exit fullscreen mode

Use it in src/routes/_middleware.js:

import { authenticate } from '../lib/auth.js';

export function handle({ request, resolve }) {
  authenticate(request);
  return resolve(request);
}
Enter fullscreen mode Exit fullscreen mode

Deployment and Configuration

SvelteKit offers flexible deployment options for platforms like Vercel, Netlify, or AWS Amplify. Configure the target platform using adapters:

// svelte.config.js
import adapter from '@sveltejs/adapter-node';

export default {
  kit: {
    adapter: adapter(),
  },
};
Enter fullscreen mode Exit fullscreen mode

Page Transitions

SvelteKit supports smooth page transitions using the <transition> and <route> components within <svelte:head>:

<svelte:head>
  <script>
    import { crossfade } from 'svelte/transition';

    export let data;
    export let component;

    let transition;
    $: transition = component ? crossfade : null;
  </script>

  {#if transition}
    <transition
      bind:this={transition}
      duration={300}
      outDuration={200}
      in={component !== data.component}
      out={component === data.component}
    >
      <slot />
    </transition>
  {:else}
    <slot />
  {/if}
</svelte:head>
Enter fullscreen mode Exit fullscreen mode

This code implements a crossfade transition, smoothly fading between pages when the component changes.

Client-Side Routing and Navigation

Use the goto function or $navigate store for client-side navigation, or apply the use:link action to <a> tags:

<script>
  import { navigate } from '$app/navigation';

  function handleClick() {
    navigate('/another-page');
  }
</script>

<button on:click={handleClick}>Go to Another Page</button>

<a href="/another-page" use:link>Another Page</a>
Enter fullscreen mode Exit fullscreen mode

Adapters

Adapters allow SvelteKit apps to be packaged for specific platforms. For example, @sveltejs/adapter-node targets Node.js servers, while @sveltejs/adapter-static generates static sites.

Service Workers and Offline Support

SvelteKit supports Progressive Web App (PWA) features, including offline support, via the @sveltejs/adapter-workbox adapter, enabling service workers for basic functionality without a network.

Static Asset Handling

SvelteKit automatically handles static assets like images, CSS, and JavaScript. Place files in the static directory, and SvelteKit copies and references them during the build. For example, static/images/logo.png is accessible at /images/logo.png.

Environment Variables and Configuration

SvelteKit supports environment variables for different environments (e.g., development, production). Define them in .env files or svelte.config.js and access them via import.meta.env:

// svelte.config.js
export default {
  kit: {
    vite: {
      define: {
        'process.env.API_KEY': JSON.stringify(process.env.API_KEY),
      },
    },
  },
};
Enter fullscreen mode Exit fullscreen mode
<script>
  console.log(import.meta.env.VITE_API_KEY);
</script>
Enter fullscreen mode Exit fullscreen mode

Type Safety and TypeScript Support

SvelteKit fully supports TypeScript for type safety. Rename .svelte files to .svelte.ts and configure TypeScript to enable type hints and error checking.

SvelteKit combines tools for building high-performance SSR applications with an excellent developer experience, flexibility, and ease of use, making it a powerful choice for modern web development.

🚀 Join my technical exchange group to get daily useful information:

Top comments (0)