SvelteKit キャッチアップ
Svelteをコンポーネントフレームワークとすると、SvelteKitはアプリケーションフレームワークと言えます。
各ページの書き方はNext.jsのApp Routerに似ていると感じました。
本質的には、SvelteKit が行う仕事は次の3つに集約されます。
ルーティング(Routing) — 受け取ったリクエストにどのルートがマッチするかを判断する
ローディング(Loading) — ルートが必要とするデータを取得する
レンダリング(Rendering) — (サーバー上で) HTML を生成する、または (ブラウザで) DOMを更新する
違う点はapp.htmlがページ全体のtemplateになっており、これに対してSvelteKitがコンポーネントの置き換えを行なっていく、というところだと思います。
Routing
src/route
内にある+page.svelte
ファイルがアプリケーションのページを作成します。
例えば/aboutでアクセスしたいページを作成するためにはsrc/route/+page.svelte
を追加すればOKです。
leyout
+layout.svelte
を作成することでそのディレクトリ配下にある+page.svelte
の共通部分を作成することができます。
動的ルーティング
[]で囲まれたディレクトリを作成することで、動的なパラメーターを持つルートを作成することができます。
例えば、src/route/user/[id]/+page.svelte
というファイルを作成することで、/user/1や/user/adminのようなルートが作成されます。
Loading Data
+page.svelte
と同じ階層にある+page.server.js
はサーバー側でデータの取得を行い、値をsvelteファイルに受け渡す。
import { posts } from '../data.js'
import { error } from '@sveltejs/kit'
export function load({ params }) {
const post = posts.find((post) => post.slug === params.slug);
if(!post) throw error(404);
return {
post
};
}
このload関数が読み取りと受け渡しを行う。(関数名は固定)
+layout.server.js
+layout.svelte
と同様に+layout.server.js
も配下のルートがよばれる前にloadが行われる。
+layout.svelte
で読み取ることができる。
Setting headers
load関数の中では、レスポンスのヘッダーに情報を追加することができる。
export function load({ setHeaders }) {
setHeaders({
'Content-Type': 'text/plain'
})
}
Setting cookies
同様にcookieの設定も行うことができます。
export function load({ cookies }) {
const visited = cookies.get('visited');
cookies.set('visited', 'true', { path: '/'});
return {
visited: visited === 'true'
};
}
cookieの設定にはcookies.set(name, value, options)
を使用します。
optionsにはこちらのドキュメントのparce,serializeオプションに対応しているようです。
Shared modules
モジュールやコンポーネントは使用するpageファイルの近くに置くのが一般的ですが、複数のページで使用されるものは共通の置き場があると便利です。
SvelteKitではそのディレクトリを、src/lib
になっています。
インポートの際には、import { name } from '$lib/name.js';
のように使用します。
Form
formが一つの場合
データの送信には通常のHTMLと同様にformタグを使用します。
<form method="POST">
<label>
add a todo:
<input
name="description"
autocomplete="off"
/>
</label>
</form>
action要素はここでは書かず+page.server.js
にactions
として記述します。
export const actions = {
default: async ({ cookies, request }) => {
const data = await request.formData();
db.createTodo(cookies.get('userid'), data.get('description'))
}
}
formが複数ある場合
defaultのみだと2種類以上のformには対応できないので名前をつけて呼び出すactionを振り分けます。
<form method="POST" action="?/create">
<label>
add a todo:
<input
name="description"
autocomplete="off"
/>
</label>
</form>
<ul class="todos">
{#each data.todos as todo (todo.id)}
<li>
<form method="POST" action="?/delete">
<input type="hidden" name="id" value={todo.id} />
<span>{todo.description}</span>
<button aria-label="Mark as complete" />
</form>
</li>
{/each}
</ul>
action要素の値は?から始まっていますが、これはroute直下にある為です。
todoディレクトリは以下にある場合は、"/todo?/create"のようになります。
export const actions = {
create: async ({ cookies, request }) => {
const data = await request.formData();
db.createTodo(cookies.get('userid'), data.get('description'));
},
delete: async ({ cookies, request }) => {
const data = await request.formData();
db.deleteTodo(cookies.get('userid'), data.get('id'));
}
};
Validation
必須項目などはHTML部分で防ぐことができます。
inputタグ内にrequiredを追加します。
<script>
export let data;
+ export let form;
</script>
<div class="centered">
<h1>todos</h1>
+ {#if form?.error}
+ <p class="error">{form.error}</p>
+ {/if}
<form method="POST" action="?/create">
<label>
add a todo:
<input
name="description"
+ value={form?.description ?? ''}
autocomplete="off"
+ required
/>
</label>
</form>
+ import { fail } from '@sveltejs/kit';
export const actions = {
create: async ({ cookies, request }) => {
const data = await request.formData();
+ try {
db.createTodo(cookies.get('userid'), data.get('description'));
+ } catch (error) {
+ return fail(422, {
+ description: data.get('description'),
+ error: error.message
+ })
+ }
},
delete: async ({ cookies, request }) => {
// ...
}
};
failでラップした値はformとして+page.svelte
に返すことができます。
enhance
import { enhance } from '$app/forms';
をしてuse:enhance
をFomrタグに追加することでページをリロードするのではなくなったため、トランジションなどが効くようになります。
use:enhance
は独自にカスタマイズを行うことができます。送信中の表示(sending...など)はこれを使って操作できます。
<form
method="POST"
action="?/create"
use:enhance={() => {
creating = true;
return async ({ update }) => {
await update();
creating = false;
};
}}
>
API Route
ディレクトリ内に+server.js
ファイルを追加し、そこでHTTP メソッド GET、PUT、POST、PATCH、DELETE に対応する関数をエクスポートすることで、 API ルート(API routes) を作成することができます。
import { json } from '@sveltejs/kit';
export function GET() {
const number = Math.floor(Math.random() * 6) + 1;
return json(number);
}
呼び出す側ではfetch('/roll');
のように、ディレクトリ名をURL部分に設定する。
Store
SvelteKit では、3つの読み取り専用 store (page、navigating、updated )を $app/stores から使用できます。
pageで取得できる情報
- url
現在のページの URL - params
現在のページのパラメータ - route
現在のルート(route)を表す id プロパティを持つオブジェクト - status
現在のページの HTTP ステータスコード - error
現在のページのエラーオブジェクト - data
現在のページの data。全ての load 関数からの戻り値が足されたもの - form
form action から返されるデータ
他の store と同様、コンポーネントでは $ シンボルを先頭に付けることでその値を参照することができます。例えば、現在のパス名は $page.url.pathname でアクセスできます:
navigatingで取得できる情報
リンクをクリックしたり、ブラウザの '戻る/進む'、またはプログラムで goto を呼んだときに値を持つ。
navigating の値は以下のプロパティを持つオブジェクトになります:
- from/to
params、route、url プロパティを持つオブジェクト - type
ナビゲーションのタイプ(link、popstate、goto)
updatedで取得できる情報
updated store は true または false を持ちます。これは最初にページを開いてからそれ以降にアプリの新バージョンがデプロイされたかどうかを表しています。動作させるには、svelte.config.js で kit.version.pollInterval を指定する必要があります。
バージョンの変更はプロダクションでのみ発生し、開発時には発生しません。そのため、このチュートリアルでは $updated は常に false となります。
pollInterval とは関係なく、updated.check() を呼び出すと手動で新バージョンがデプロイされたかチェックできます。
error
SveltKitには想定される(expected)エラーと、予期せぬ(unexpected)エラーの二種類があります。
-
expected error
想定されているエラーは500以外のエラーのことです。
エラーの原因がわかっているものなので適切なエラーコードと共にthrowします。+page.server.jsimport { error } from '@sveltejs/kit'; export function load() { throw error(420, 'Enhance your calm'); }
-
unexpected error
予期せぬエラーの場合は、アプリのバグであると考えられます。予期せぬエラーがスローされた場合、そのメッセージとスタックトレースがコンソールにログ出力されます。
画面にはエラーの内容ではなく、'Internal Error' メッセージと 500 ステータスコードが表示されます。
+error.svelte
src/routes/+error.svelte コンポーネントを作成することで、エラーページをカスタマイズすることができます。
エラーが起きた階層から一番近い+error.svelte
ページが表示されます。
最上位(root)のレイアウトでデータをロードしているときや、エラーページのレンダリング中にエラーが発生した場合、SvelteKit は静的なエラーページにフォールバックします。
src/error.html
ファイルを作成することで、フォールバックエラーページをカスタマイズすることができます。
<h1>Game over</h1>
<p>Code %sveltekit.status%</p>
<p>%sveltekit.error.message%</p>
このファイルは以下の項目を含めることができます。
%sveltekit.status% — HTTP ステータスコード
%sveltekit.error.message% — エラーメッセージ
redirect
throwの仕組みを応用して、別ページへのリダイレクトを行うことができます。
throw redirect(dode,route)
は、load 関数、form actions、API ルート、そして後の章で説明する handle hook の内側で使うことができます。
よく使用されるステータスコードはこちらです。
- 303
form actions で、送信に成功したあと続いて使用されます - 307
一時的なリダイレクトに使用されます - 308
恒久的なリダイレクトに使用されます