storybook/docs/get-started/sveltekit.md
2024-03-11 13:17:35 -06:00

12 KiB
Raw Blame History

title
Storybook for SvelteKit

export const SUPPORTED_RENDERER = 'svelte';

Storybook for SvelteKit is a framework that makes it easy to develop and test UI components in isolation for SvelteKit applications. It includes:

  • 🪄 Zero config
  • 🧩 Easily mock many Kit modules
  • 🔗 Automatic link handling
  • 💫 and more!

Storybook for SvelteKit is only supported in Svelte projects.

Requirements

  • SvelteKit ≥ 1.0 (not including beta versions)
  • Storybook ≥ 7.0

Getting started

In a project without Storybook

Follow the prompts after running this command in your Sveltekit project's root directory:

<CodeSnippets paths={[ 'common/init-command.npx.js.mdx', 'common/init-command.yarn.js.mdx', 'common/init-command.pnpm.js.mdx', ]} />

More on getting started with Storybook.

In a project with Storybook

This framework is designed to work with Storybook 7+. If youre not already using v7, upgrade with this command:

<CodeSnippets paths={[ 'common/storybook-upgrade.npm.js.mdx', 'common/storybook-upgrade.pnpm.js.mdx', 'common/storybook-upgrade.yarn.js.mdx' ]} />

Automatic migration

When running the upgrade command above, you should get a prompt asking you to migrate to @storybook/sveltekit, which should handle everything for you. In case that auto-migration does not work for your project, refer to the manual migration below.

Manual migration

First, install the framework:

<CodeSnippets paths={[ 'svelte/sveltekit-install.npm.js.mdx', 'svelte/sveltekit-install.pnpm.js.mdx', 'svelte/sveltekit-install.yarn.js.mdx' ]} />

Then, update your .storybook/main.js|ts to change the framework property:

<CodeSnippets paths={[ 'svelte/sveltekit-add-framework.js.mdx', 'svelte/sveltekit-add-framework.ts.mdx' ]} />

Finally, these packages are now either obsolete or part of @storybook/sveltekit, so you no longer need to depend on them directly. You can remove them (npm uninstall, yarn remove, pnpm remove) from your project:

  • @storybook/svelte-vite
  • @storybook/svelte-webpack5
  • storybook-builder-vite
  • @storybook/builder-vite

Supported features

All Svelte language features are supported out of the box, as the Storybook framework uses the Svelte compiler directly. However, SvelteKit has some Kit-specific modules that aren't supported. Here's a breakdown of what will and will not work within Storybook:

Module Status Note
$app/environment Supported version is always empty in Storybook.
$app/forms Supported See How to mock.
$app/navigation Supported See How to mock.
$app/paths Supported Requires SvelteKit 1.4.0 or newer.
$app/stores Supported See How to mock.
$env/dynamic/public 🚧 Partially supported Only supported in development mode. Storybook is built as a static app with no server-side API, so it cannot dynamically serve content.
$env/static/public Supported
$lib Supported
@sveltejs/kit/* Supported
$env/dynamic/private Not supported This is a server-side feature, and Storybook renders all components on the client.
$env/static/private Not supported This is a server-side feature, and Storybook renders all components on the client.
$service-worker Not supported This is a service worker feature, which does not apply to Storybook.

How to mock

To mock a SvelteKit import you can define it within parameters.sveltekit_experimental:

// MyComponent.stories.svelte
export const MyStory = {
  parameters: {
    sveltekit_experimental: {
      stores: {
        page: {
          data: {
            test: 'passed',
          },
        },
        navigating: {
          route: {
            id: '/storybook',
          },
        },
        updated: true,
      },
    },
  },
};

The available parameters are documented in the API section, below.

The default link-handling behavior (e.g. when clicking an <a href="..." /> element) is to log an action to the Actions panel.

You can override this by assigning an object to parameters.sveltekit_experimental.hrefs, where the keys are strings representing an href and the values define your mock`. For example:

// MyComponent.stories.svelte
export const MyStory = {
  parameters: {
    sveltekit_experimental: {
      hrefs: {
        '/basic-href': (to, event) => {
          console.log(to, event);
        },
        '/root.*': {
          callback: (to, event) => {
            console.log(to, event);
          },
          asRegex: true,
        },
      },
    },
  },
};

Writing native Svelte stories

Storybook provides a Svelte addon maintained by the community, enabling you to write stories for your Svelte components using the template syntax. You'll need to take some additional steps to enable this feature.

Run the following command to install the addon.

<CodeSnippets paths={[ 'svelte/svelte-csf-addon-install.yarn.js.mdx', 'svelte/svelte-csf-addon-install.npm.js.mdx', 'svelte/svelte-csf-addon-install.pnpm.js.mdx', ]} />

The community actively maintains the Svelte CSF addon but still lacks some features currently available in the official Storybook Svelte framework support. For more information, see addon's documentation.

API

Parameters

This framework contributes the following parameters to Storybook, under the sveltekit_experimental namespace:

forms

Type: { enhance: TK }

Provides mocks for the $app/forms module.

forms.enhance

Type: TK

A callback that will called when a form with use:enhance is submitted.

hrefs

Type: Record<[path: string], (to: string, event: TK) => void | { callback: (to: string, event: TK) => void, asRegex?: boolean }>

If you have an <a /> tag inside your code with the href attribute that matches one or more of the links defined (treated as regex based on the asRegex property) the corresponding callback will be called. See Mocking links for an example.

navigation

Type: TK

Provides mocks for the $app/navigation module.

navigation.goto

Type: TK

A callback that will be called whenever goto is called. If no function is provided, an action will be logged to the Actions panel.

navigation.pushState

Type: TK

A callback that will be called whenever pushState is called. If no function is provided, an action will be logged to the Actions panel.

navigation.replaceState

Type: TK

A callback that will be called whenever replaceState is called. If no function is provided, an action will be logged to the Actions panel.

navigation.invalidate

Type: TK

A callback that will be called whenever invalidate is called. If no function is provided, an action will be logged to the Actions panel.

navigation.invalidateAll

Type: TK

A callback that will be called whenever invalidateAll is called. If no function is provided, an action will be logged to the Actions panel.

navigation.afterNavigate

Type: TK

An object that will be passed to the afterNavigate function, which will be invoked when the onMount event fires.

stores

Type: { navigating?: {}, page?: {}, updated?: boolean }

Provides mocks for the $app/stores module.

stores.navigating

Type: TK

A partial version of the navigating store.

stores.page

Type: TK

A partial version of the page store.

stores.updated

Type: boolean

A boolean representing the value of updated (you can also access stores.check() which will be a noop).

Options

You can pass an options object for additional configuration if needed:

// .storybook/main.js
import * as path from 'path';

export default {
  // ...
  framework: {
    name: '@storybook/sveltekit',
    options: {
      // ...
    },
  },
};

The available options are:

builder

Type: Record<string, any>

Configure options for the framework's builder. For Sveltekit, available options can be found in the Vite builder docs.

Troubleshooting

Error when starting Storybook

When starting Storybook after upgrading to v7.0, it may quit with the following error:

ERR! SyntaxError: Identifier '__esbuild_register_import_meta_url__' has already been declared

This can occur when manually upgrading from 6.5 to 7.0. To resolve it, you'll need to remove the svelteOptions property in .storybook/main.js, as that is not supported (and no longer necessary) in Storybook 7+ with SvelteKit.

Error in preview canvas

When running Storybook, some stories may not load. Instead they show the following error in the preview canvas:

Cannot read properties of undefined (reading 'disable_scroll_handling')

You'll experience this if anything in your story is importing from $app/forms or $app/navigation, which is currently not supported. To get around this, separate your component into a shallow parent component that imports what's needed and passes it to a child component via props. This way you can write stories for your child component and mock any of the necessary modules by passing props in.