Skip to content

SvelteKit

  • Basic Svelte

    • Introduction
      • A UI framework that allows you to build your app out of components
      • A component is a reusable self-contained block of code that encapsulates HTML, CSS, and JavaScript written into a `.svelte` file
      • Components compile into JS modules
      • Write CSS in <style> tags, JS in <script> tags inside components
      • Style rules are scoped to the component
      • Component names are capitalized
      • Render HTML directly into a component with `{@html …}` tag
    • Reactivity
      • Svelte has a reactivity system to keep the DOM in sync with the application state
    • Declare derived state with reactive declarations — reactive values - let count = 0;

      $: doubled = count * 2;

  • Valuable when needs to reference them multiple times

  • Reactive declarations and statements will run after other script code and before component markup is rendered

  • Can also run arbitrary statements reactively — log statements to if blocks

  • Svelte’s reactivity is triggered by assignments — array methods won’t trigger it

    • Simple rule of thumb: the name of the updated variable must appear on the left-hand side of the assignment
  • Props

    • Pass data through the component tree with props
    • Declare props with `export` keyword
    • Specify default values for props
      • export let answer = ‘a mystery’;
  • Logic

  • Conditional render markup with `if` block

    • {#if …}…{:else if}…{:else}…{/if}
    • # is a block opening tag
    • / is a block closing tag
    • : is a block continuation tag
  • Render list with `each` block

    • {#each listObj as listItem, index (listItem.id)}…{/each}
    • listItem.id is key to tell Svelte how to figure out which DOM node to change when the component updates
  • Await values of promises inside `await` block

    • {#await promise}
      <p>…waiting</p>
      {:then number}

      <p>The number is {number}</p>

      {:catch error}

      <p style=“color: red”>{error.message}</p>

      {/await}

  • {#await promise then number}

    <p>The number is {number}</p>

    {/await}

  • If a second promise is made before the first is resolved, Svelte only considers the most recent promise → no race condition

  • Events

    • Listen to DOM events on an element with the `on:` directive
    • DOM event handlers can have modifiers to alter their behaviour
      • preventDefault --- calls event.preventDefault() before running the handler. Useful for client-side form handling, for example.
      • stopPropagation --- calls event.stopPropagation(), preventing the event reaching the next element
      • passive --- improves scrolling performance on touch/wheel events (Svelte will add it automatically where it’s safe to do so)
      • nonpassive --- explicitly set passive: false
      • capture --- fires the handler during the capture phase instead of the bubbling phase
      • once --- remove the handler after the first time it runs
      • self --- only trigger handler if event.target is the element itself
      • trusted --- only trigger handler if event.isTrusted is true, meaning the event was triggered by a user action rather than because some JavaScript called element.dispatchEvent(…)
    • Chain modifiers together, e.g. `on:click|once|capture={…}`
    • Create custom event handlers for components with event dispatcher
      • createEventDispatcher must be called when the component is first instantiated
    • Component events don’t bubble up like DOM events, listen to custom events on deeply nested components by having intermediate components forward the event
      • An `on:message` event directive without a value means ‘forward all message events’
      • This also works with DOM events
  • Bindings

    • Use `bind:` directive for two-way bindings, e.g: form elements
      • Also performs type checks for you
    • Bind group of radio or checkbox inputs with `bind:group`
  • Lifecycle

    • Svelte provides functions to run code at key moments during a component’s lifecycle
      • onMount --- runs after the component is first rendered to the DOM
      • beforeUpdate --- schedules work to happen immediately before the DOM is updated
      • afterUpdate --- runs code once the DOM is in sync with your data
      • tick --- returns a promise that resolves as soon as any pending state changes have been applied to the DOM
  • Stores

    • Values that need to be accessed by multiple unrelated components, or by a regular JS module
    • A store is an object with a `subscribe` method that allows interested parties to be notified whenever the store value changes
    • Writable stores also have `set` and `update` methods
    • Not unsubscribing can cause memory leak
    • Svelte handles unsubscribing with auto-subscription — reference a store value by prefixing the store name with `$`
      • Only works with store variables that are declared at the top-level scope of a component
    • Readable stores prevent writing by users
    • Create derived stores with `derived`
    • As long as an object correctly implements the `subscribe` method, it’s a store → very easy to implement custom stores to centralize store logic
    • If a store is writable, it can bind to its value
  • Advanced Svelte

    • Motion
      • `svelte/motion` and `svelte/easing` modules
      • Change stores or reactive values to `tweened` values
      • Use `spring` instead of `tweened` for frequently changing values
    • Transitions
      • ‘svelte/transition’ modules
      • Use `transition` directive
      • `fade`, `fly`, etc.
      • `in` and `out` directives for in and out transitions
      • Can write custom CSS and JS transitions
      • Svelte dispatches events for transitions for you to listen to
        • `introstart`
        • `introend`
        • `outrostart`
        • `outroend`
      • Key blocks destroy and recreate their contents when the value of an expression changes
        • {#key i}…{/key}
    • Special elements
      • <svelte:self> allows a component to contain itself recursively
      • <svelte:window> refers to the window object
      • <svelte:body> refers to document.body
        • Useful for mouseenter and mouseleave events, which don’t fire on window
      • <svelte:document> refers to document
        • Useful for selectionchange event, which doesn’t fire on window
      • <svelte:head> refers to the <head>
        • Useful for <title> and <meta> tags, critical for good SEO
      • <svelte:fragment> element allows you to place content in a named slot without wrapping it in a container DOM element.
  • SvelteKit

    • SvelteKit apps are server-rendered by default and transition to client-side navigation when the user navigates
      • Has 3 main jobs
        • Routing — figuring out which route matches an incoming request
        • Loading — get the data needed by the route
        • Rendering — generate some HTML (on the server) or update the DOM (in the browser)
    • Routing
      • Filesystem-based routing
      • Every +page.svelte file inside src/routes creates a page in your app
      • +layout.svelte component applies to all routes in the same directory
        • The <slot /> element is where the page content will be rendered
        • Applies to every child route
        • Can nest layouts to arbitrary depth
      • Create routes with dynamic parameters with square brackets around a valid variable name
        • Multiple route parameters can appear within one URL segment, as long as they are separated by at least one static character: foo/[bar]x[baz]
    • Loading data
      • Page data
        • Every page of your app can declare a load function in a +page.server.js alongside the +page.svelte file
        • This module only runs on the server, including for client-side navigation
        • Load data from a database or a CMS
        • Access loaded data inside +page.svelte via the data prop
        • Access dynamic route parameters by declaring params argument in load function
        • Users that visit an invalid pathname can respond with a 404 page with the error helper
      • Route data
        • +layout.server.js files load data for every child route
    • Headers & cookies
      • Set headers inside a load function, form actions, hooks, and API routes with setHeaders()
      • Use the cookies API for cookies-related stuff
    • Shared modules
      • Because SvelteKit uses directory-based routing, it’s easy to place modules and components alongside the routes that use them
      • For modules that are used in multiple places, put them in src/lib directory, and access them from anywhere in src via the $lib alias
    • Forms
      • Define server-side actions to handle POST request inside +page.server.js
      • The request is a standard WebAPI Request object
      • Define named form actions with action=”?/<actionName>” in the form and add <actionName> : <action> in actions object in +page.server.js
      • The action attribute can be any URL — even if the action was defined on another page
      • Validate form data with the browser’s built-in form validation → server-side validation
        • SvelteKit hides unexpected error messages from server-side validation (throw new Error(…)) from users because they contain sensitive data
        • Better to provide an indiction of what went wrong with the fail function → return data from the action along with an appropriate HTTP status code (return fail(400, {…})
        • Access the returned value via the form prop → only populated after a form submission
        • You can also return data from a form action without wrapping it in fail which will also be available via the form prop → useful for showing successful submissions
      • Add use:enhance directive to <form> elements to progressively enhance users’ experience and emulate the browser-native behaviour except for full-page reloads
        • Update the form prop
        • Invalidate all data on a successful response, causing load functions to re-run
        • Navigate to the new page on a redirect response
        • Render the nearest error page if an error occurs
        • Provide a callback to use:enhance to add pending states, optimistic UI, cancel() submissions, handle redirects, control whether the form is reset, and so on
    • API routes
      • Create API routes by exporting functions corresponding to HTTP methods: GET, PUT, POST, PATCH, DELETE in a +server.js file
      • Request handlers must return a Response object
      • Handlers that mutate data, such as POST should be implemented with form actions for less verbose and more resilient code
    • Stores
      • SvelteKit makes three readonly stores available via the $app/stores module — page, navigating, and updated
      • page provides information about the current page
        • url — the URL of the current page
        • params — the current page’s parameters
        • route — an object with an id property representing the current route
        • error — the error object of the current page
        • data — the data for the current page, combining the return values of all load functions
        • form — the data returned from a form action
    • Errors
      • There are two types of errors in SvelteKit — expected errors and unexpected errors
      • Expected errors
        • Create with the error helper from @sveltejs/kit
        • Expected errors’ messages are shown to the users
      • Unexpected errors
        • Create with standard WebAPI Error constructor
        • Unexpected errors’ messages are redacted and replaced with a generic ‘Internal Error’ message and a 500 status code
      • When the load function fails to run, SvelteKit renders an error page
        • Customize the error page with +error.svelte file
      • When the root layout data fails to load, or while rendering the error page, SvelteKit will fall back to a static error page
        • Customize the fallback error page with src/error.html file
      • Redirect with throw redirect(…) with redirect helper
        • Use inside load functions, form actions, API routes, and the handle hook
        • Common status codes
          • 303 --- for form actions, following a successful submission
          • 307 --- for temporary redirects
          • 308 --- for permanent redirects
  • Advanced SvelteKit

    • Hooks
      • SvelteKit provides several hooks — ways to intercept and override the framework’s default behavior
      • handle — the most elementary hook
        • Lives in src/hooks.server.js
        • Receives an event object along with a resolve function, and returns a Response
        • resolve is where SvelteKit matches the incoming request URL to a route of your app, imports the relevant code, loads the data needed by the route, and generates the response