Storybook&SvelteでTypescript/Sassを使う場合の注意点


※ 当ページには【広告/PR】を含む場合があります。
2024/07/12
StorybookでSvelteプロジェクト向けのUIデザイン開発環境を構築する
蛸壺の技術ブログ|Storybook&SvelteでTypescript/Sassを使う場合の注意点

前回の内容までで、フレームワークをSvelteに指定する際のStorybookをインストールする方法を解説してみました。

合同会社タコスキングダム|蛸壺の技術ブログ
StorybookでSvelteプロジェクト向けのUIデザイン開発環境を構築する

フロントエンドワークショップ環境・『Storybook』をSvelteで使うためのインストール手順

これでSvelteコンポーネントでもStorybookが使えるようにはできたものの、多少無理をして構築したStorybook(v7)/Viteの組み合わせでは、TypescriptとSassの取り扱いには注意が必要になります。

今回もStorybookの使い方に直接は関係しない話題ですが、SvelteをTypescript/Sass等を使って開発したい方は事前に知っておきたいポイントをまとめてみます。


合同会社タコスキングダム|蛸壺の技術ブログJavascript(js)&Typescript(ts)プログラミング入門〜これから学ぶ人のためのおすすめ書籍&教材の手引き

超JavaScript 完全ガイド 2024

StorybookでTypescriptを使う

Storybookでは標準で内部のTypescriptを使って、リソースフォルダ内の.tsファイルをトランスパイルしてくれる仕組みになっています。

このため、Typescriptを使うだけなら何も問題ありませんが、場合によっては外部のライブラリを使いたい際に、Vite側の設定をカスタマイズする必要も出てきます。

Storybookのvite-buildersでViteの振る舞いを独自に制御する方法

StorybookのVite設定を独自に定義するための方法がいくつか用意されています。

参考|Vite - Storybook

Viteをカスタマイズする場合には、
@storybook/builder-viteを追加し、

            
            yarn add -D @storybook/builder-vite
        
として、例えば以下のように内部のViteの設定をviteFinal関数を介して調整します。

            
            import { mergeConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default {
    //...中略
    core: {
        builder: '@storybook/builder-vite', //👈ビルダーを有効化
    },
    //...中略
    //👇vite.config.jsのカスタマイズ
    async viteFinal(config) {
        return mergeConfig(config, {
            plugins: [svelte()],
        });
    }
}
        
通常はこのviteFinalを使って、必要な設定を追加していく方式で変更を加えるのが一般的のようです。

またVite設定の変更点が多い場合、以下のように
vite.config.jsをごっそり入れ替えるやり方も可能です。

            
            export default {
    //...中略
    core: {
        //👇独自のvite.config.jsを外部ファイルから指定する
        builder: {
            name: '@storybook/builder-vite',
            options: {
                viteConfigPath: './customVite.config.js',
            },
        },
    },
    //...中略
}
        

Storybook/Viteのバージョンによってはモジュールの読み込みに失敗する

前回の内容からもSvelte/ViteでStorybookを動かすだけでなんだかとっても疲れてしまいました。

このように現状もStorybook自体がかなり対応できていないバグの温床になっています。

例えば、先程のカスタムVite設定から
@sveltejs/vite-plugin-svelteを読み込ませようとすると、Storybook(v7)のファイルローダーがきちんとパッケージを読み込んでくれません。

            
            @storybook/cli v7.6.20

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in ./node_modules/@sveltejs/vite-plugin-svelte/package.json
    at exportsNotFound (node:internal/modules/esm/resolve:294:10)
    at packageExportsResolve (node:internal/modules/esm/resolve:584:13)
    at resolveExports (node:internal/modules/cjs/loader:591:36)
    at Module._findPath (node:internal/modules/cjs/loader:668:31)
    at Module._resolveFilename (node:internal/modules/cjs/loader:1130:27)
    at Module._resolveFilename (./node_modules/esbuild-register/dist/node.js:4799:36)
    at Module._load (node:internal/modules/cjs/loader:985:27)
    at Module.require (node:internal/modules/cjs/loader:1235:19)
    at require (node:internal/modules/helpers:176:18)
    at Object.<anonymous> (./.storybook/main.js:2:24)
        
別段、@sveltejs/vite-plugin-svelte側には問題なさそうなのですが、「exportsが定義されていない」と不条理なエラーが吐き出させると後はどう対応することもできません。

Viteがカスタマイズできないので、Svelteユーザーにとっては少し困ったことに、Svelteコンポーネントへの埋め込みのTypescriptコードがStorybookに上手く解釈されません。

例えば、以下のようなSvelteコンポーネントを利用しようとしても、

            
            <script lang="ts">
    export let label: any;
</script>

...
        
Storybookにはこのスクリプト部分はすべてJavascriptと解釈させるため、コンパイルが通りません。

            
            [vite] Internal server error: /usr/src/app/storybook/stories/components/Button/Button.svelte:2:20 Unexpected token
  Plugin: vite-plugin-svelte
  File: /usr/src/app/storybook/stories/components/Button/Button.svelte:2:20
   1 |  <script lang="ts">
   2 |      export let label: any;
                            ^
   3 |  </script>
   4 |
        
このため、SvelteプロジェクトにStorybookを統合したいのではあれば、「Svelteコンポーネントの埋め込みスクリプトにはTypescriptを使わない」ことが推奨されます。

どうしてもTypescriptコードを使いたい場合、ロジックをTSファイルに分離して、Svelteコンポーネント側でインポートするやり方で対応しましょう。

例えば、Svelteコンポーネントと同階層に
index.tsを新規作成し、そこに外部関数を準備しておきます。

            
            export function toggle(e: any) {
    const items = [...document.getElementsByClassName('hoge')];
    console.log(items);
}
        
間接的なやり方ですが、これをSvelteコンポーネント側で呼び出して利用することが可能です。

            
            <script>
    //👇tsコードから読み込んだ関数
    import {toggle} from './index';
</script>

<ul>
    <li>
        <span class="hoge" on:click={toggle}>Hoge</span>
    </li>
</ul>
        

合同会社タコスキングダム|蛸壺の技術ブログJavascript(js)&Typescript(ts)プログラミング入門〜これから学ぶ人のためのおすすめ書籍&教材の手引き

超JavaScript 完全ガイド 2024

StorybookでSassを使う

Storybook/ViteでSassコードを使いたい場合、いくつかのpeerDependancyになっているライブラリを入れる必要があります。

Sassをインストール

以前の
Svelteプロジェクトのセットアップ方法でも触れたように、Sassのインストール作業自体は同じです。

            
            $ yarn add -D sass postcss autoprefixer
        
これでStorybook内部のViteがSassコードを自動で認識してくれるようになります。

使い方はSvelteコンポーネントと同層に
style.scssなどとファイルを新規作成しておき、

            
            .hoge {
    cursor: pointer;
    user-select: none;
    &::before {
        content: "\25B6";
        color: black;
        display: inline-block;
        margin-right: 6px;
    }
}
        
このスタイルを読み込む際には、Svelteコンポーネントのスクリプトタグで行います。

            
            <script>
    //👇scssコードから読み込んだスタイル
    import './style.scss';
</script>

<ul>
    <li>
        <span class="hoge">Hoge</span>
    </li>
</ul>
        

「<style lang="scss">」では動かない

先ほどのTypescriptのパートでも説明していましたが、
@sveltejs/vite-plugin-svelteが正常に動かない影響で、埋め込みのstyleタグに直接Sassを指定してもCSSとして認識されるため、期待通りに動きません。

            
            <style lang="scss">
.hoge {
    cursor: pointer;
    user-select: none;
    &::before {
        content: "\25B6";
        color: black;
        display: inline-block;
        margin-right: 6px;
    }
}
</style>

<ul>
    <li>
        <span class="hoge">Hoge</span>
    </li>
</ul>
        
SvelteとStorybookを利用する場合、CSSをそのまま使わないならばstyleタグを利用せずに、できるだけ外部ファイルからscriptタグで読み込ませて使いましょう。


合同会社タコスキングダム|蛸壺の技術ブログJavascript(js)&Typescript(ts)プログラミング入門〜これから学ぶ人のためのおすすめ書籍&教材の手引き

超JavaScript 完全ガイド 2024

まとめ

以上、今回もSvelteとStorybookの開発環境構築の話題となってしまいました。

Storybookの現行のリリースバージョンはv8ですが、サポートするフレームワークの種類が多く、しかも内部のバンドラーにWebpackとViteが選べるという大きなメリットの代償として、放置されたバグも非常に多い印象です。

ただし、Storybookに変わるほどの有力なフロントエンドワークショップはまだ現れてはいなさそうですので、開発者の創意工夫でStorybookと上手く付き合っていくしかないのも事実です。

よって、初期の段階からStorybook側に考慮した形でSvelteプロジェクトを開発できるように心がけることが重要と言えるでしょう。
記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。

合同会社タコスキングダム|蛸壺の技術ブログJavascript(js)&Typescript(ts)プログラミング入門〜これから学ぶ人のためのおすすめ書籍&教材の手引き