祝バージョン1.0リリース🎉 サンプルアプリから学ぶSvelteKit

この記事は「[【マイスター・ギルド】本物のAdvent Calendar 2022](https://adventar.org/calendars/7794)」19日目の記事です。

こんにちはSvelte大好きなmiruoonです。普段は[Zenn](https://zenn.dev/miruoon_892)の方にSvelte記事を投稿していますが、会社の行事ということでこちらで投稿しています。

SvelteKitが先日2年以上の開発を経て、ついにバージョン1.0に到達しました！

https://svelte.dev/blog/announcing-sveltekit-1.0

（日本語版は[こちら](https://svelte.jp/blog/announcing-sveltekit-1.0)）

Nuxt.js 3もこの前バージョン1.0に到達していたばかりなので、ここ最近のReact/Next.js一強状態に近くなりつつあるフロントエンドフレームワーク界に新しい風を吹き込んでくれることでしょう。

そんなSvelteKitを今回改めて紹介していきたいと思います。

# 記事の注意点

- Svelteを初めて間もない人でも読めるレベル感にしています
- そのため、使い分けがややこしい`+page.ts` / `+page.server.ts`については一旦簡単な使い分け程度に記載をとどめています
- フレームワークの立ち位置上、Next.jsの言及が度々登場します。ご留意ください。

# そもそもSvelteとはなにか

読みは「スベルト（`/ˈsvɛlt/`）」です。スリムで魅力的なことを意味する[英単語](https://www.vocabulary.com/dictionary/svelte)が由来です。
知らない人も多いと思うので、簡単ですが紹介します。

**仮想DOMを使用せず、「生のJavaScriptにコンパイルしてくれる」UIフレームワークです。**

そのため、コンパイル後のJSファイルのサイズが小さくなり、よってビルドも早くなるのが強みとなっています。また、「Write less code（コードを少なく）」というスローガンを上げており、フレームワーク特有の書き方が少なく短いコードでコンポーネントを書くことが出来ます[^1]。

そうした強みからStackOverflowの開発者調査など様々な調査でReactを凌ぎ、最も愛されるフロントエンドフレームワークとして高い評価を頂いています。

https://insights.stackoverflow.com/survey/2021#web-frameworks

その他開発チーム公認の日本語翻訳コミュニティが活発で、公式ドキュメントを日本語ですぐキャッチアップできる環境が整っています。

ともかく、[チュートリアル](https://svelte.jp/tutorial/basics)[^2]の出来がかなりいいので気になる人は今すぐにでもやってください。Svelteの良さがすぐに理解できると思います。

# SvelteKitとは？

ここからが本題。
Svelteと組み合わせて使うアプリケーションフレームワークになります。React でいうところの Next.js/VueでいうNuxt.jsのような立ち位置に当たります。

SvelteKitの特徴として以下が挙げられます。
- 柔軟なファイルシステムによるルーティングやSSR, SSGをサポート
- SSR, SSGを組み合わせて、ページごとに片方だけ/両方使用するを選択できる
- ビルドツールにはViteを採用。なのでViteのpluginもそのまま使える
- プロジェクト作成時には TypeScript/ESLint/Prettier/Vitest[^3] を追加するかどうか選択可能
- 1行追加するだけで、アプリをPWA対応に出来る
- adapter機能により、各サービス（Vercel, Netlify, Firebaseなど）に対応したデプロイが簡単にできる

実際アプリの構成はどうなの？って感じなので、一度例となるプロジェクトを作成してみます。皆さんも環境構築してサンプルアプリを触りながら記事を読み進めてもらえばと思います。

# 開発環境

:::note warn
2022年12月現在、Node.jsバージョン16.14〜18のみ対応しています。
古いバージョンだと次のようなメッセージが出て、アプリの環境構築が出来ないのでご注意ください。

```bash
@sveltejs/kit@1.0.1: The engine "node" is incompatible with this module. Expected version "^16.14 || >=18". Got "16.10.0"
```
:::

- MacBook Pro (13-inch, M1, 2020)
- macOS Monterey 12.1
- Node.js v18.12.1
- Yarn v1.22.19
- またTypeScriptを使用しています

# プロジェクトを作成する

次のコマンドから作成できます。

```zsh
$ npm create svelte@latest sample-app
```

色々質問が飛んでくるので、今回はデモアプリが入った雛形を導入します。
今回テストコードは書かないので、VitestおよびPlaywrightは導入しません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/31ff44f4-9614-7b41-48ff-4e447d2d1117.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/4a68efa0-27ab-27d0-adf8-b45efabba557.png)

最後に親切にパッケージのインストール〜アプリの立ち上げ手順が親切に表示されるので、こちらに従っていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/86e35641-1375-b91f-282e-6d8152f14126.png)


```zsh
$ yarn
$ yarn dev
```

リッチでオレンジなカウンターアプリが表示されたら完了です🎉。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/d324706d-5b67-55c4-5b8f-8b6e22c792a0.png)

# ディレクトリ構成の説明

まず生成されたアプリのディレクトリ構成はこんな感じなっているはずです。

```markdown
sample-app/
├ src/
│ ├ lib/
│ │ ├ images/
│ ├ routes/
│ │ └ about/
│ │ └ sverdle/
│ │ └ +layout.svelte
│ │ └ +page.svelte
│ │ └ +page.ts
│ │ └ Counter.svelte
│ │ └ Header.svelte
│ │ └ styles.css
│ ├ app.html
│ ├ error.html
│ └ hooks.js
├ static/
├ package.json
├ svelte.config.js
├ tsconfig.json
└ vite.config.js
```

このうち、SvelteKitの特徴となる箇所を中心に抜粋して紹介していきます。簡単なものから順に説明していきます。

https://kit.svelte.dev/docs/project-structure

※[日本語版](https://kit.svelte.jp/docs/project-structure)

## `static` フォルダ

アセットファイルを設置するファイルになります。今のところfavicon関連のファイルを設置するケースが多めですが、Svelteの公式サイトのソースコードでは画像ファイルがここに集約されているので、静的なアセットファイルなら何を置いても大丈夫なようです。

https://github.com/sveltejs/sites/tree/master/sites/svelte.dev/static

このフォルダにあるファイルは`%sveltekit.assets%`を使って簡単に呼び出すことが出来ます。しっかりpath指定のやり方が決まっている点は有り難いです。

```html
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
```

## `src/lib`フォルダ

ライブラリのコードを入れるフォルダとなります。このフォルダに格納すると`$lib`エイリアスを使って、簡単にimportすることが出来ます。`import * from '../../../../Hoge.svele'`みたいに書く必要がなくなるので、非常に便利です。

実際のサンプルコードではこんな形で実際に使用されています。

```html:src/routes/Header.svelte
<script>
	import logo from '$lib/images/svelte-logo.svg';
</script>
```

いろんな箇所でimportすることになるファイルをここに設置すると良いかと思います。

## `src/app.html`ファイル

アプリ内のすべてのページのテンプレートとなるファイルになります。
Next.jsでいう`_document.[j|t]sx`に当たります。

`<body>`を設置できるのは本ファイルのみです。`<head>`タグの大半もここで記載します。
サンプルコードではこんな形で記載されています。ここからすべてのページに必要な`<meta>`タグの追記などが可能になっています。

```html:src/app.html
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
		<meta name="viewport" content="width=device-width" />
		%sveltekit.head%
	</head>
	<body data-sveltekit-preload-data="hover">
		<div style="display: contents">%sveltekit.body%</div>
	</body>
</html>
```

ところで一部見慣れない単語がここで出てきました。一つずつ見ていきましょう。

### `%sveltekit.assets%`

staticフォルダの紹介でも少し登場しました。staticフォルダの絶対パスを表しています。

### `%sveltekit.head%`

これは後述しますが、各ページのテンプレートファイルに`<svelte:head>`というタグが登場します。`<svelte:head>`タグの中身の埋め込みを意味します。

### `%sveltekit.body%`

各ページのテンプレートファイルに記載されたマークアップ内容（=レンダリングされたDOM要素）がここに埋め込まれます。
間違いやすいですが、**`<body>`タグ直下ではなく、その子要素となる`<div>`タグ直下に設置する**点にはご注意ください。

## `src/routes`フォルダ

いよいよSvelteKitアプリの中心となる場所に来ました。
Next.jsでいう`pages`フォルダに当たる箇所ではあるのですが、SvelteKit特有の特徴がたくさん存在している箇所になるため、順を追って説明していきます。

### ルーティング

配置するフォルダによって自動的にルーティングが生成される仕組みとなります。
ここはNext.js/Nuxt.jsを触ったことがあればすぐ馴染めると思います。

配置の仕方は以下のとおりです。

- `src/routes` はrootルーティング（=`/`のルート）を主に表す。他に全ルート共通のスタイルシートや共通レイアウトもここに設置。
- `src/routes/about` -> `/about`ルート
- `src/routes/blog/[slug]` -> slugパラメータを使ったルートを作成します。たとえば`/blog/hello-world` のようなページを生成することが出来ます。

フォルダ構成の説明をしたところで、実際に設置するファイルの説明をしていきます。

### `+layout.svelte`

SvelteKitのルールとして、各ルートのファイルには`+`という接頭辞が付くことになっています。その最初の例がこの`+layout.svelte`となります。

ヘッダー・フッダーの設置など全ページ共通のレイアウトを司るファイルとなります。

立ち位置としてはNext.jsの`_app.[j|t]sx`と同じです。

サンプルコードではこの形になってます。ヘッダー/フッターの設置および`<slot>`タグを使って各ページの表示を可能にしていることがわかります。

```html:src/routes/+layout.svelte
<script>
	import Header from './Header.svelte';
	import './styles.css';
</script>

<div class="app">
	<Header />

	<main>
		<slot />
	</main>

	<footer>
		<p>visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to learn SvelteKit</p>
	</footer>
</div>
```

### `+page.svelte`

各ページの定義を行うファイルとなります。Next.jsとは異なり、ファイル名は`+page.svelte`で固定です。

サンプルアプリから一番簡単なaboutページを例に出してみます。

```html:src/routes/about/+page.svelte
<svelte:head>
	<title>About</title>
	<meta name="description" content="About this app" />
</svelte:head>

<div class="text-column">
	<h1>About this app</h1>

	<p>
		This is a <a href="https://kit.svelte.dev">SvelteKit</a> app. You can make your own by typing the
		following into your command line and following the prompts:
	</p>

	<pre>npm create svelte@latest</pre>

	<p>
		The page you're looking at is purely static HTML, with no client-side interactivity needed.
		Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening
		the devtools network panel and reloading.
	</p>

	<p>
		The <a href="/sverdle">Sverdle</a> page illustrates SvelteKit's data loading and form handling. Try
		using it with JavaScript disabled!
	</p>
</div>
```

実際のブラウザではこのように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/3d2fc351-0bcd-16ac-c543-0b0a22d35707.png)

`<svelte:head>`を使ってページ固有の`<title>`および`<meta>`タグの定義を行ってから、マークアップ部分の表示が行われていることがわかります。


### `+page.ts` / `+page.server.ts`

SvelteKitでおそらく一番ややこしいであろうファイルの登場です。
ともに`+page.svelte`がレンダリングされる前に実施したい処理を記載します。

少しでも簡単に説明するために各ファイルの違いを見ていきます。深堀りしていくとややこしくなっていく箇所なので今回の記事範囲では以下の認識で大丈夫です。

- `+page.server.ts`

-> データベースやファイルシステムからデータを直接アクセスする必要がある場合や、プライベートな環境変数を使用する必要がある場合に使われる。サーバーサイドレンダリング（SSR）して常に最新情報を持っていきたいっていうページはこっち。

- `+page.svelte`

-> クライアント・サーバー両方使うページで設置。認証をせずにただ外部のAPIからデータをfetch (取得)するだけならこちらが推奨されている。主にJS/TSを一切使わない静的なページにおいても設置。

### その他ルーティングフォルダの特徴

ルーティングフォルダってただ上記で上げたファイルしか設置できないんでしょ？って思った人もいるかもしれません。実はページの部品となるコンポーネントファイルやメソッドが入ったJS/TSファイルも置くことができるんです[^4]。

実際のサンプルアプリでもこんな形で`+`のついていない普通の`svelte`ファイルが存在することが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/bb49b172-4294-b3c9-a369-16b767868a66.png)

そのため、機能ごとのフォルダを作って関連するファイルを集約することも可能になっています。フロントエンド設計的な観点でもファイルがバラけてしまわないように設計が出来ることが期待出来ます。

サンプルアプリを読む上で知っておくべきSvelteKitの特徴となるディレクトリ/ファイルの説明は以上になります。

# もっと知りたい人へ

- `+page.ts` / `+page.server.ts`の使い分け

このファイルについてはルーティングや非同期処理に関する機能がとにかく多く、これだけ1記事作れそうなくらい濃いファイルになっています。もう少し詳しく知りたい方はこちらの公式ドキュメントのページに詳細が記載されているので、合わせて読んでみてください。

https://kit.svelte.dev/docs/load#universal-vs-server

[※日本語版](https://kit.svelte.jp/docs/load#universal-vs-server-when-to-use-which)

- 本記事で紹介できなかった機能について

今回はSvelte初めて間もない人でもサンプルアプリに新しいページを作る形で進めてみました。ですが`adapter`機能など実は紹介できてない機能がまだまだあります。
もっと知りたい方は公式ドキュメントや下記のAwesome一覧にある先人たちが作成したアプリに触れてみるといいでしょう。筆者からもどこかのタイミングで情報を逐次お伝えできればと思います。

https://awesome-sveltekit.janosh.dev/

なおSvelte本体に続き、Svelteitに関してもチュートリアルが作成中とのこと。完成が楽しみなところです。

# 活用事例

最後に活用事例を紹介します。
国内サイトでもチラホラ事例が出てきている印象です。1.0に到達したことで今後本格的に事例が増えていくことが予想されます。

- [KINTO コーポレートサイト](https://corp.kinto-jp.com/)
  - トヨタの自動車サブスクサービスを行っていることでご存知の人も多いと思います。
  -  [解説記事](https://blog.kinto-technologies.com/posts/2022_09_06_svelte_newpost/) 
- [新規プロジェクトのフロントエンドにSvelteKitを採用しました](https://tech.macloud.jp/entry/2022/08/30/122131)

# 参考ページ
- [SvelteKit + microCMS のブログ作成チュートリアル](https://blog.microcms.io/sveltekit-tutorial/)
- [SvelteKitのデフォルトプロジェクトから学ぶ](https://future-architect.github.io/articles/20220415a/)

[^1]: 詳しく知りたい方は[公式による記事](https://svelte.jp/blog/write-less-code)を読んでみてください。
[^2]: まだ実験段階かつ英語のみですが、さらに[リッチに進化した新チュートリアル](https://learn.svelte.dev/tutorial/welcome-to-svelte)もあります
[^3]: 知らない人のために説明しておくと、Vite専用のJestみたいなライブラリです。
[^4]: 試しているアプリを見つけられてないので、確証は持てないですが、ViteベースなのでおそらくCSS Modulesファイルも置くことが出来ると思います。