SvelteKitの基本を Svelte Tutorialで学ぼう

2022年12月15日に、SvelteKitが正式リリースされました。SvelteKitは、ReactのNext.jsやVue.jsのNuxt等と同様に、SvelteというJavaScriptライブラリを利用したフレームワークです。

複数のページで構成されるWebサイトを制作したり、データベースと連携したアプリを開発したりでき、Next.jsやNuxtに比べるとシンプルで作りやすい印象があります。

ここでは、Svelteを学習できる「Svelte Tutorial」のSvelteKitのセクションを進めながら、説明が英語なので日本語で補足をしていきましょう。

Svelteチュートリアルを起動しよう

Svelteチュートリアルは、Svelteのドキュメントからアクセスできます。

最初はSvelte自身のチュートリアルが展開されるので、SvelteKitのチュートリアルは次のページから始まります。

すると、左側に説明が、右側にエディター(上部)とブラウザー(下部)に展開されます。上部のエディターのファイルを変更すると、すぐに下のWebブラウザで確認できます。

例えば今、<h1>要素があるので内容を書き換えると、リアルタイムに書き換わることが確認できます。

Svelteを体験しよう

SvelteKitを利用して生成されたページには、Svelteを利用する事ができます。Svelteでは、{ ... }という記述を埋め込むと、変数の内容を等をリアルタイムに反映できます。まずは、次のように変数を宣言しましょう。Svelteでは、ファイルの上部に<script>タグを埋め込めます。

<script>
    let name = 'ともすた'
</script>

<h1>Welcome to tomosta</h1>
...

そしたら、本文内に次のように埋め込んでみましょう。

...
<h1>Welcome to { name }</h1>

変数の内容を変更すれば、リアルタイムに書き換わります。

ファイルの構成を確認しよう

SvelteKitはインストールすると、次のようなフォルダーやファイルが自動で生成されます。

  • src/app.html
    このファイルが実際にWebブラウザに表示されます<head>要素を変えたい場合などはこのファイルを変更します
  • src/routes
    各ページのファイルが格納されます
  • static
    画像ファイルなどのリソースファイルなどを格納します
  • svelte.config.js
    SvelteKitの設定ファイルです

この他、Node.jsの設定を行う「package.json」と、Viteというビルドツールの設定ファイルである「vite.config.js」が設置されていますが、これらについてはここでは省略します。「Node.js」や「Vite」などを学習しましょう。

ページを増やそう

左側の画面下にある、次ページへのリンクを何度かクリックして「Pages」というページまで移動しましょう。図のように、「home」と「about」というナビゲーションがあるページが表示されます。

しかし、現状では「about」をクリックしてもページが見つかりません。そこで、このアドレスにページを追加しましょう。

SvelteKitは、src/routesフォルダーの中に特定の名前でフォルダーやファイルを作成すると、自動的にアドレスが生成されるしくみです。例えば、/aboutというアドレスを作りたい場合は、/src/フォルダーの中にaboutという名前のフォルダーを作成します。

そしたら、このフォルダーの中に+page.svelteという名前のファイルを作成しましょう。ファイル名の先頭が「+」になっていたり、拡張子が.svelteとなっていますが、このファイル名で固定になっています。

これでファイルを作れば、すぐにアクセスができるようになります。後はこのファイルに内容を作っていけば、ページを増やすことができます。

レイアウトファイルを使おう

次ページにアクセスしましょう。

サイト内で使う共通のパーツなどの場合は、個別に作成するよりは共通パーツにした方が良いでしょう。このような時は、レイアウトファイルを利用できます。

src/routesフォルダーに+layout.svelteファイルを作成しましょう。すると、//aboutが真っ白のページに変わりますが、すでにレイアウトファイルが採用されるようになっています。

各ページの内容を反映するには<slot />という特別なタグを使います。

<slot />

このタグの前後には、共通のパーツを追加することができます。例えばここでは、src/routes/+page.svelteファイルに書かれているナビゲーションを設置してみましょう。<nav>要素全体を切り取って、+layout.svelteに貼り付けておきましょう。

<nav>
<a href="/">home</a>
<a href="/about">about</a>
</nav>

<slot />

パラメータを指定できるようにしよう

次ページにアクセスしましょう。

こうして、ページを増やしていく事はできますが、例えばブログのしくみを作ろうとした場合、各記事の内容はページとしては存在せずに、別のヘッドレスCMSやデータベースからデータを取得する事がほとんどです。

そのため、/blog/oneとか/blog/twoなど、さまざまなアドレスを指定したときにも対応できるようにしましょう。これには、パラメータを受け取れるようにします。/src/routes/blogフォルダーに、[slug]というフォルダーを作成しましょう。

このフォルダーの中に、これまでと同様に+page.svelteファイルを作成してページ内容を作成しましょう。これで、/blog/oneなどのアドレスが指定されたときに、このファイルが表示されるようになります。

JSONファイルと連携しよう

次ページにアクセスしましょう。

では、ブログの記事を外部のデータから取得しましょう。ここでは、JSONデータから取得します。ブログ記事はsrc/routes/blog/data.jsファイルに準備されています。これを読み込んで、一覧画面を作成してみましょう。

まずは、これを読み込むためのプログラムを作成します。これには/src/routes/blog/+page.server.jsというファイル名で作成しましょう。

次のように書き込みます。

import { posts } from './data.js';

export function load() {
    return {
        summaries: posts.map((post) => ({
            slug: post.slug,
            title: post.title
        }))
    };
}

すると、同じ場所にある+page.svelteファイルからdataとして受け取ることができるようになります。/src/routes/blog/+page.svelteファイルを次のように変更しましょう。

<script>
    export let data;
</script>

<h1>blog</h1>

<ul>
    {#each data.summaries as { slug, title }}
        <li><a href="/blog/{slug}">{title}</a></li>
    {/each}
</ul>

各個別のページも同じように作成します。/src/routes/blog/[slug]フォルダーに+page.server.jsファイルを作成します。

import { posts } from '../data.js';

export function load({ params }) {
    const post = posts.find((post) => post.slug === params.slug);

    return {
        post
    };
}

ここではfindメソッドを使って、URLで指定されているパラメーター(slug)と一致するデータだけを取得しています。

後は、/src/routes/blog/[slug]/+page.svelteは次のようになります。

<script>
    export let data;
</script>

<h1>blog post</h1>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>

本文を表示している{@html ...}というのは、データの中にHTMLのタグがあった場合に、そのまま内容を表示するというプレースホルダーです。これを使う場合、データ内の安全性がSvelteでは保障されなくなるため、注意をして利用しましょう。必要に応じて、手作業でエスケープ処理などをする必要があります。

不正なパラメーターが指定されたときにページが見つからない処理をしよう

現状、アドレスを書き換えて不正な内容などに変更すると、JSONのデータが取得できないため「Internal Error」が発生してしまいます。しかし、実際にはページの削除などもあるため、一般的なページが見つからない場合のエラー処理をしていきましょう。これには/src/routes/blog/[slug]/+page.server.jsに次のように記述して、404エラーコードを返却します。

export function load({ params }) {
    const post = posts.find((post) => post.slug === params.slug);

    if (!post) throw error(404); // 追加

    return {
        post
    };
}

共通して利用するデータをロードしよう

各ページで利用したいデータは、先の通り+page.server.jsというファイルを準備しますが、もし一覧でも個別のページでも共通して利用したいデータがある場合は、+layout.server.jsというファイルが利用できます。

まずは、/src/routes/blog/+page.server.js/src/routes/blog/+layout.server.jsに名前を変えましょう。これで、他のファイルからも参照ができるようになります。

そしたら、/src/routes/blog/[slug]/+layout.svelteに次のように追加します。

<script>
    export let data;
</script>

<div class="layout">
    <main>
        <slot />
    </main>

    <aside>
        <h2>More posts</h2>
        <ul>
            {#each data.summaries as { slug, title }}
                <li>
                    <a href="/blog/{slug}">{title}</a>
                </li>
            {/each}
        </ul>
    </aside>
</div>

これで、各ページに最新のエントリーが表示されるようになります。

スタイルシートを調整しよう

Svelteでは、スタイルシートも.svelteファイルに書き込み事ができます。一番下に追加しましょう。

...
<style>
    @media (min-width: 640px) {
        .layout {
            display: grid;
            gap: 2em;
            grid-template-columns: 1fr 16em;
        }
    }
</style>

これで、サイドエリアに移動しました。

<以下、執筆中>