静的サイトは、速度、セキュリティ、そしてシンプルさに優れていることから、近年ますます人気が高まっています。静的サイト作成用ツールやフレームワークは多数ありますが、中でも急速に人気を伸ばしているのがSvelteKitです。

今回はセットアップからKinstaの静的サイトホスティングでのデプロイ方法まで、SvelteKitを使用した静的サイトの作り方を詳しくご紹介していきます。

SvelteKitで構築できる静的サイト例
SvelteKitで構築できる静的サイト例

SvelteKitとは

SvelteKit、静的サイトを含むユーザーインターフェースを作成するための堅牢なウェブフレームワーク。パフォーマンス、シンプルさ、宣言的なアプローチでコンポーネントを構築可能です。

ルーティングやサーバーサイドレンダリングなどを実装することで、機能を拡張することもできます。

SvelteKitで静的サイトを構築する

これからご紹介する手順では、以下の条件を前提とします。

それでは、早速手順を見ていきましょう。

  1. 以下を実行して新規プロジェクトを立ち上げます。
npm create svelte@latest my-app

my-appディレクトリにプロジェクトが作成され、TypeScriptなどの基本的なツールの設定が求められます。「Skeleton project」を選択し、my-appをプロジェクト名に変更します。

  1. プロジェクトディレクトリに移動し、依存関係をインストール。
cd my-app
npm install
  1. npm run devを実行して、localhost:5173上のローカル開発サーバーを起動します。
SvelteKitのスケルトンサイト
SvelteKitのスケルトンサイト

SvelteKitのファイル構造

プロジェクトをコードエディターで開くと、以下のような構造になっています。コードを効率的に整理するため、この構造は把握しておきましょう。

/
|-- /src
    |-- /lib
    |-- /routes
        |-- +page.svelte
    |-- app.html
|-- /static
|-- svelte.config.js
  • /src:プロジェクトの中核となり、様々なサブディレクトリとファイルが格納される。
    • /lib:カスタムライブラリ、ユーティリティ、またはモジュールが格納される。アプリケーション全体で使用する再利用可能なコードを保管するのに適しています。
    • /routes:アプリケーションの異なるページやビューの定義に重要。各ページは+page.svelteのような.svelteファイルで表され、この.svelteファイルには、各ページ固有のコンポーネント、ロジック、スタイルが含まれます。
    • app.html:アプリケーションのエントリーポイントとして機能。ウェブページの主な構造が定義されます。
  • /static:画像、フォント、アプリケーションで処理する必要のないファイルなどの静的アセットを保存。これらのアセットは、HTMLやSvelteコンポーネントで直接参照できます。
  • svelte.config.js:SvelteKitプロジェクトの様々な側面をカスタマイズ可能。サーバーサイドレンダリングの設定、カスタムレイアウトの定義などに使用できます。

SvelteKitのルーティング

ルーティングシステムは、SvelteKitの目玉機能。ファイルシステムベースのルーティングにより、URLパスがsrc/routesディレクトリ内のファイルやフォルダで定義され、直感的かつ簡単に管理することができます。

SvelteKitでは、ルートに対応するファイル名は必ず「+page.svelte」でなければなりません。例えば、SvelteKitサイトのインデックスファイルはroutesフォルダにあり、名前は+page.svelteです。

このファイルに以下のコードを追加して、サイトのトップページを作成します。


<div class="home_hero">
    <h1>insta StSHで静的サイトホスティングをお楽しみください</h1>
    <p>高速、安全、信頼性に優れたホスティングソリューション</p>
    <a href="https://kinsta.com/jp/static-site-hosting/">
        <div class="btn">もっと詳しく</div>
    </a>
</div>

<style>
    .home_hero {
        display: flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
        text-align: center;
    }
    .home_hero h1 {
        font-size: 60px;
        width: 70%;
    }
    .home_hero p {
        color: #6e7076;
        font-size: 20px;
    }
    .btn {
        background-color: #5333ed;
        padding: 20px 30px;
        margin-top: 40px;
        border-radius: 5px;
        color: #fff;
    }
    @media (max-width: 700px) {
        .home_hero h1 {
            font-size: 40px;
        }
        .home_hero p {
            font-size: 16px;
        }
    }
</style>

SvelteKitでネストされたルート、例えばlocalhost:5173/aboutでアクセスできる会社概要ページを作成するには、routesフォルダ内にURLパスを表す名前のフォルダを作成し、フォルダ内にルート用にレンダリングされる+page.svelteファイルを作ります。

続いて、routes/about/+page.svelteに以下のコードを貼り付けます。

<div class="about_cont">
    <h2>About</h2>
    <div class="about_info">
        <div class="about_text">
            <p>
                Kinstaで最大100件まで{' '}
                <a> href="https://kinsta.com/jp/static-site-hosting/">
                    静的サイトを無料でホスティング
                </a>{' '}
                お好きなGitサービス(Bitbucket、GitHub、またはGitLab)に
                コードをプッシュして、Kinstaにデプロイするだけ。
            </p>
            <p>
                静的サイトホスティングの代わりに{' '}
                <a> href="https://kinsta.com/jp/application-hosting/">
                    アプリケーションホスティング
                </a>
                でデプロイすることもできます。
                柔軟なスケーリング、Dockerfileを使用したデプロイメントのカスタマイズ、
                リアルタイムおよび過去のデータを網羅した包括的な分析など
                堅牢な機能が多数揃っているため、ホスティングの柔軟性が高まります。
            </p>
        </div>
        <iframe> width="560" height="315" src="https://www.youtube.com/embed/H7CNbsda8OA?si=40FGVlNvJ74_6hlj" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen> </iframe>
    </div>
</div>

<style>>
    .about_cont h2 {
        font-size: 40px;
        margin-bottom: 20px;
    }
    .about_info {
        display: flex;
        width: 100%;
        justify-content: space-between;
        gap: 20px;
    }
    @media (max-width: 700px) {
        .about_info {
            flex-direction: column;
        }
    }
    .about_text {
        flex-basis: 50%;
    }
    .about_text p {
        margin-bottom: 20px;
        font-size: 18px;
    }
    .about_img {
        flex-basis: 50%;
        width: 200px;
        border-radius: 10px;
    }
    @media (max-width: 700px) {
        .about_info {
            flex-direction: column;
        }
        .about_img {
            width: 100%;
        }
    }
</style>

Svelteコンポーネントに追加されたスタイルは、スコープが制限されているため、他のコンポーネントに影響を与えることはありません。

SvelteKitは、標準的な<a>要素を使用してページ間のナビゲーションを処理し、ナビゲーションプロセスを直感的に理解します。Reactで必要になる<Link>のような追加コンポーネントをインポートする必要はありません。次のセクションでは、各ページに追加するナビゲーションコンポーネントを構築していきましょう。

現在のプロジェクトでは、ルート構造は次のようになっています。

|-- /src
    |-- /routes
        |-- /about
            |-- +page.svelte
        |-- +page.svelte

SvelteKitでコンポーネントを使用する

コンポーネントを作成してページにインポートすることで、コードをよりモジュール化することができます。例として、routesフォルダにNavbar.svelteコンポーネントを構築してみます。


<nav>
    <a href="/">
        <img src="/kinsta-logo.png" alt="" class="logo-img" />
    </a>
    <div class="nav-links">
        <a href="/">ホーム</a>
        <a href="/about">会社概要</a>
        <a href="/posts">投稿</a>
    </div>
</nav>

以下のように+page.svelteトップページにインポートします。


<script>>
    import Navbar from './Navbar.svelte'
</script>

<Navbar />
<div class="home_hero">
    <h1>Kinsta StSHで静的サイトホスティングをお楽しみください</h1>
    <p>高速、安全、信頼性に優れたホスティングソリューション</p>
    <a href="https://kinsta.com/jp/static-site-hosting">
        <div> class="btn">もっと詳しく</div>
    </a>
</div>

<style>
      /* CSS styles */
</style>

NavbarFooterなど、複数のファイルにまたがって使用されるグローバルコンポーネントは、長いインポートパスを避けるためにsrc/libフォルダに作成してください。libフォルダ内にコンポーネントやモジュールを作成すると、$libインポートエイリアスを使用して全てのコンポーネントにインポートできるため便利です。

<script>
    import Navbar from '$lib/Navbar.svelte'
</script>

スタンドアロンコンポーネントを使う場合、例えば、会社概要ページにのみ必要であれば、routes/aboutルート内で作成してページにインポートします。

libフォルダにFooterコンポーネントを作成し、以下のコードを追加することも可能です。

<div class="footer">
    <p>
        Hosted with ❤️ by Kinsta's{' '}
        <a> href="https://kinsta.com/jp/static-site-hosting">静的サイトホスティング</a>
        .
    </p>
</div>

それから、すべてのページにインポートしてください。

SvelteKitでレイアウトを使用する

多くのページにコンポーネントをインポートするのを避けるため、SvelteKitでは+layout.svelteファイルを使ってページのレイアウトを定義することができます。

各ページに適用するレイアウトの作成は簡単で、src/routes/+layout.svelteという名前のファイルを作成し、任意のマークアップ、スタイル、動作でカスタマイズしていきます。重要な要件として、ページのコンテンツを追加するために<slot/>要素を含めてください。

例えば、NavbarFooterコンポーネントをレイアウト内に統合することができます。

<script>
    import Navbar from '$lib/Navbar.svelte';
    import Footer from '$lib/Footer.svelte';
</script>

<div class="layout">
    <Navbar />
    <slot />
    <Footer />
</div>

<slot>要素を使って、各ページのコンテンツをレイアウトに挿入することができます。

また、特定のページに対して入れ子にすることも。例えば、/dashboardページがあり、/profile/settingsのようなページが入れ子になっている場合、特別なレイアウトを作成することができます。

|-- /dashboard
    |-- /profile
        |-- +page.svelte
    |-- /settings
        |-- +page.svelte
    |-- +layout.svelte

SvelteKitのプログラマティックナビゲーション

SvelteKitには、プログラムナビゲーション用のgoto関数があり、たとえばログインアクション後、/dashboardページに移動する場合は、以下のようになります。

<script>
    import { goto } from '$app/navigation';
    
    async function login() {
        // ログイン操作の実行
        goto('/dashboard');
    }
</script>

SvelteKitのスタイリング

SvelteKitでは、従来のCSSによるスタイリングをサポートしています。<style>タグを使ってSvelteコンポーネント内でスタイルを定義することもできれば、外部のスタイルシートをリンクすることも可能です。

お気づきのかもしれませんが、NavbarFooter コンポーネントには特定のスタイルがありません。スタイルを変更するには、グローバルスタイルを適用するのがお勧めです。srcフォルダ内にCSSファイルを作成し、ルートレイアウトファイルにインポートしましょう。

わかりやすいよう、srcディレクトリ内にstylesフォルダを作成してすべてのスタイルを格納します。stylesフォルダ内にglobal.cssファイルを作成し、以下のコードを貼り付けます。

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500&display=swap');
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
body {
    background-color: #ddd;
    font-family: 'Poppins',
        sans-serif;
    width: 1200px;
    margin: 0 auto;
}
a {
    text-decoration: none;
}
img {
    width: 100%;
}
nav {
    display: flex;
    justify-content: space-between;
    height: 200px;
    align-items: center;
}
nav .logo-img {
    width: 100px;
}
nav .nav-links a {
    padding: 0 20px;
    font-size: 18px;
}
@media (max-width:700px) {
    body {
        width: 100%;
        padding: 0 20px;
    }
    nav .nav-links a {
        padding: 0 18px;
    }
}
.footer {
    width: 100%;
    text-align: center;
    margin: 100px 0 20px;
}

このCSSファイルをレイアウトファイルにインポートすると、グローバルスタイルとなり、すべてのファイルで機能するように。

<script>>
    import Navbar from '$lib/Navbar.svelte';
    import Footer from '$lib/Footer.svelte';
    import '../styles/global.css';
</script>

SvelteKitでデータを読み込む方法

SvelteKitを使用する場合は、レイアウトやページ、コンポーネントにデータを読み込む必要があります。データは外部API、データベース、またはローカルサーバから取得でき、管理にはページ用の+page.jsファイルとレイアウト用の+layout.jsファイルを使用します。

+page.svelteファイルは、load関数をエクスポートする兄弟ファイル+page.jsを持つことができます。この関数の戻り値は、data propsを通してページで利用可能です。以下、JSON Placeholder APIから投稿一覧を取得するルートを作成してみます。

APIからデータを読み込むため、postsフォルダ内に+page.jsファイルを作成します。このファイルがload 関数をエクスポートします。

export const load = async () => {
    const title = "Hello World";
    return {
        title,
    };
};

load関数はオブジェクトを返すことが期待されており、オブジェクトは+page.svelteファイルにpropsとして提供されます。titleの値は、data propsで可能です。

<script>>
    export let data;
    const title = data.title;
</script>

<div class="blog_cont">
    <h2>{title}</h2>
</div>

続いては、JSON Placeholder posts APIとのやり取りです。これにはJavaScript Fetch APIを使用しますが、SvelteKitには独自のfetch関数があり、ページをレンダリングする前にAPIエンドポイントからデータを取得することができます。

export const load = async (loadEvent) => {
    const { fetch } = loadEvent;
    const response = await fetch(
        'https://jsonplaceholder.typicode.com/posts?_limit=10'
    );
    const posts = await response.json();
    return {
        posts,
    };
};

上のコードでは、loadEventからfetch関数を抽出し、APIリクエストを行います。っています。レスポンスは投稿ページにpropsとして送信され、すべての投稿をループして表示します。

<script>
    export let data;
    const posts = data.posts;
</script>

<div class="blog_cont">
    <h2>投稿</h2>
    <div class="blog_grid">
        {#each posts as post}
            <a href={`/posts/${post.id}`} class="blog_card">
                <h3>{post.title}</h3>
                <p>
                    {post.body}
                </p>
            </a>
        {/each}
    <;/div>
<;/div>

<style>
    .blog_cont h2 {
        font-size: 40px;
        margin-bottom: 20px;
    }
    .blog_grid {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        gap: 20px;
    }
    @media (max-width: 700px) {
        .blog_grid {
            grid-template-columns: 1fr;
        }
    }
    .blog_card {
        background-color: #bfbfbf;
        padding: 20px;
        border-radius: 5px;
        color: #000;
        transition: all 0.5s ease-in-out;
    }
    .blog_card:hover {
        background-color: #5333ed;
        color: #fff;
    }
    .blog_card h3 {
        margin-bottom: 15px;
    }
    .blog_card p {
        margin-bottom: 15px;
    }
</style>

この時点で、ファイルツリーは以下のようになっています。

|-- /src
    |-- /lib
        |-- Footer.svelte
        |-- Navbar.svelte
    |-- /routes
        |-- /about
            |-- +page.svelte
        |-- /posts
            |-- +page.js
            |-- +page.svelte
        |-- +page.svelte
        |-- +layout.svelte
    |-- /styles
        |-- global.css

SvelteKitによる動的ルーティング

現在、投稿ページには10件の投稿が表示されるようになっています。各投稿ごとに個別のページを作成するには、動的ルーティングを設定するのがベストです。

これにはルートからスラッグ値を受け取り、それをパラメータとして投稿をクエリが必要ですが、SvelteKitでは、パラメータ名の角括弧([])のフォルダを作成します。手順は以下のとおりです。

  1. postsフォルダ内に[postid]フォルダを作成。[postid]は動的パラメータを表し、投稿IDやスラッグのような値を保持することができます。
  2. [postid]フォルダの中に以下2つのファイルを作成。
    • +page.svelte:個々の投稿ページのレイアウトと構造を定義
    • +page.js:個々の投稿に特有のデータ取得とロジックを処理

page.jsファイルでは、postidパラメータをルートから取得し、特定の投稿をクエリするために使用します。

">export const load = async (loadEvent) => {
    const { fetch, params } = loadEvent;
    const { postid } = params;
    const response = await fetch(
        `https://jsonplaceholder.typicode.com/posts/${postid}`
    );
    const post = await response.json();
    return {
        post,
    };
};

その後、+page.svelteファイルのpropsとしてdataにアクセスします。

<script>>
    export let data;
    const post = data.post;
</script>

<;div>
    <;div class="blog_content">
        <h3>{post.title}</h3>
        <p>{post.body}</p>
    </div>
</div>

<style>>
    .blog_content h3 {
        font-size: 40px;
        margin-bottom: 20px;
        text-align: center;
    }
</style>

今回ご紹介したSvelteKitプロジェクトのソースコードの全貌はこちらをご覧ください。また、詳細はSvelteKitの公式ドキュメントで確認してみてください。

KinstaでSvelteKit静的サイトをデプロイする方法

Kinstaでは、任意のGitサービス(BitbucketGitHub、またはGitLab)から直接、最大100件まで静的サイトを無料でホスティングすることができます。

SvelteKitサイトを稼働する前に、デプロイメントのターゲットに合わせることが重要です。今回はKinstaの静的サイトホスティングを使用するため、SvelteKitを静的サイトジェネレーター(SSG)として設定します。

静的ファイルのコレクションとして事前にレンダリングされたサイトを取得する方法は以下のとおりです。

  1. 以下のコマンドを実行して、@sveltejs/adapter-staticをインストールします。
sh">npm i -D @sveltejs/adapter-static
  1. svelte.config.jsファイルのadapter-autofallbackから404.htmlに置き換えます。
js">import adapter from '@sveltejs/adapter-static';

const config = {
    kit: {
        adapter: adapter({ fallback: '404.html' }),
    },
};

export default config;

続いて、コードをお好きなGitサービスにプッシュしたら、以下の手順に従って、静的サイトをKinstaにデプロイします。

  1. MyKinstaにログイン、またはアカウントを作成
  2. GitサービスでKinstaを認証
  3. MyKinstaの左サイドバーから「静的サイト」を選択し「サイトを追加」をクリック
  4. デプロイしたいリポジトリとブランチを選択
  5. サイトに一意の名前を割り当てる
  6. ビルド設定に以下を追加
    • ビルドコマンドnpm run build
    • Nodeのバージョン18.16.0
    • 公開ディレクトリbuild
  1. サイトを作成」をクリック

以上で完了です。これで数秒以内にサイトがデプロイされ、サイトにアクセスするためのリンクが表示されます。必要に応じて、独自ドメインSSL証明書を追加することも可能です。

また、静的サイトホスティングの代わりに、Kinstaのアプリケーションホスティングで静的サイトをデプロイすることもできます。柔軟なスケーリング、Dockerfileを使用したデプロイメントのカスタマイズ、リアルタイムおよび過去のデータを網羅した包括的な分析など、高度な機能が多数揃っています。

まとめ

開発環境のセットアップからデプロイまで、SvelteKitで静的サイトを構築する手順をご紹介しました。この記事を参考に、ぜひ静的サイトを作成してみてください。パフォーマンスとシンプルさの完璧な融合を実現するSvelteKisなら、多くのユーザーを惹きつける優れた静的サイトの構築が簡単です。

過去にSvelteKitを使用したことはありますか?以下のコメント欄でお聞かせください。

Joel Olawanle Kinsta

Kinstaでテクニカルエディターとして働くフロントエンド開発者。オープンソースをこよなく愛する講師でもあり、JavaScriptとそのフレームワークを中心に200件以上の技術記事を執筆している。