前提
- デザイナーはTypeScriptに詳しくない
- リリース後の運用(UIの変更など)をデザイナーが行う
+page.svelte
SvelteKitではroutesディレクトリ配下に+page.svelte
を配置するとページを作成することができます。
また、+page.svelte
はただのSvelteコンポーネントなので他のファイルからimport
することができます。
この記事はそれを利用してみる内容となっています。
特定のページでしか使用しないコンポーネント
今回例としてLPのようなページを考えます。このLPは他のページと完全に独立しています。
また、lp/_components/
に配置したPosts.svelte
やlp/+page.server.ts
はlp/+page.svelte
でしか使用しないものとします。
このような状況ではlpディレクトリの近くにPosts.svelte
を置くのがいいと考えています。
今後共通で使用することがないとわかっている、かつ他で使って欲しくないコンポーネントを離れた別の場所に置きたくないためです。
この状況下ではPosts
コンポーネントのprops
に関しても
+page.server.ts -> +page.svelte -> Posts.svelte
と流れてくる以外ないので、Posts.svelte
コンポーネントのprops
の型も+page.svelte
から持ってきてしまってよいでしょう。
つまりこうです。
<script lang="ts">
import type { ComponentProps } from 'svelte';
import type Page from '../+page.svelte';
type PageDataPosts = ComponentProps<typeof Page>['data']['posts'];
let { posts }: { posts: PageDataPosts } = $props();
</script>
+page.server.ts
は以下です。
declare const __brand: unique symbol;
type BrandedType<T, B> = T & { [__brand]: B };
type PostId = BrandedType<number, 'id'>;
type UserId = BrandedType<number, 'userId'>;
type Post = {
id: PostId;
title: string;
body: string;
userId: UserId;
};
type PageServerData = {
posts: Post[];
};
export const load = async (): Promise<PageServerData> => {
const posts = await fetch('https://jsonplaceholder.typicode.com/posts/').then(
(response) => response.json()
);
return {
posts: posts.slice(0, 10),
};
};
Post
型のid
やuserId
にはBrandedTypeを使用しておりかつその型をexport
していないので、
今後例えばPosts.svelte
を拡張したXXXPosts.svelte
を「TypeScriptに詳しくないデザイナー」が作成した時に既存のPosts.svelte
のprops
を見に行くように誘導できるので少し安心です。
また、Posts.svelte
のprops
に+page.svelte
の型を使用することによって、このコンポーネントが+page.svelte
のデータを表示することを明示できました。
まとめ
このような使い方をする機会はあまりないと思いますが、+page.svelte
の型の再利用や+page.svelte
をStorybookで表示するなどのテクニックとして覚えておいて損はありません。
個人的には+page.svelte
や+layout.svelte
に色々書きすぎるとStorybookでの表示やテストの時にしんどくなると思っており、Page.svelte
やLayout.svelte
コンポーネントを作って+page.svelte
はそのページのPage.svelte
を読み込んでいるだけ、+layout.svelte
は極力使用しない という選択肢もありだと思っています。
この記事はこういうこともできるよ というアイデア、知識として読んでもらえればと思います。
最後まで読んでくださりありがとうございました!
みなさんのちょっと変わったSvelteKit、Svelteの使い方の記事も読みたいのでぜひ書いてください🙏