SvelteKitで$libを使ってデータと型を整理した話

SvelteKitの基礎を学ぶ中で、同じデータが複数ファイルに重複して書かれている問題に気づきました。 この記事では src/lib/ フォルダと $lib エイリアスを使ってデータと型を整理する方法をまとめます。

問題:同じデータが2箇所にある

記事一覧・詳細ページを作ったとき、posts の配列データが2つのファイルにそれぞれ書かれていました。

src/routes/+page.svelte         ← ここに posts がある
src/routes/posts/[id]/+page.ts  ← ここにも同じ posts がある

記事を追加・修正するたびに2箇所を直す必要があり、修正漏れが起きやすい状態です。

$lib とは

src/lib/ フォルダに置いたファイルは、プロジェクト内のどこからでも $lib/ファイル名 でimportできます。

// 相対パスだと階層によって変わる
import { posts } from '../../lib/posts';

// $lib を使えば常に同じ書き方
import { posts } from '$lib/posts';

$lib は SvelteKit が用意しているエイリアスで、src/lib/ の絶対パスに解決されます。階層の深いファイルから参照するときでも書き方が変わりません。

ファイル構成

src/
  lib/
    posts.ts    # 記事データと型(新規作成)
    todo.ts     # Todo型(新規作成)
  routes/
    +page.svelte
    posts/[id]/
      +page.ts
    todo/
      +page.server.ts

Step 1: 記事データを $lib に切り出す

src/lib/posts.ts を新規作成して、データと型をまとめます。

// src/lib/posts.ts
export type Post = {
  id: number;
  title: string;
  body: string;
};

export const posts: Post[] = [
  { id: 1, title: 'SvelteKitとは', body: 'SvelteKitはフルスタックフレームワークです。' },
  { id: 2, title: 'ルーティング入門', body: 'ファイルベースのルーティングを使います。' },
  { id: 3, title: 'load関数の使い方', body: 'データ取得はload関数で行います。' },
];

Post とデータ posts をそれぞれ export します。

Step 2: +page.svelte を修正する

ファイル内に直接書いていた posts の定義を削除して、$lib/posts からimportします。

<!-- src/routes/+page.svelte(修正後) -->
<script lang="ts">
  import { posts } from '$lib/posts';
</script>

<h1>記事一覧</h1>

<ul>
  {#each posts as post}
    <li>
      <a href="/posts/{post.id}">{post.title}</a>
    </li>
  {/each}
</ul>

const posts = [...] の定義がまるごと消えて、import の1行に置き換わります。テンプレート部分は変わりません。

Step 3: +page.ts を修正する

同様に、posts の定義を削除して $lib/posts からimportします。

// src/routes/posts/[id]/+page.ts(修正後)
import { error } from '@sveltejs/kit';
import type { PageLoad } from './$types';
import { posts } from '$lib/posts';

export const load: PageLoad = ({ params }) => {
  const post = posts.find(p => p.id === Number(params.id));

  if (!post) error(404, '記事が見つかりません');

  return { post };
};

Step 4: Todo型も $lib に移す

Todo 型は +page.server.ts の中に直接書かれていました。アプリが大きくなると他のファイルでも同じ型を使いたくなるため、src/lib/todo.ts に切り出します。

// src/lib/todo.ts
export type Todo = {
  id: number;
  title: string;
};

+page.server.ts 側は型定義を削除して $lib/todo からimportします。

// src/routes/todo/+page.server.ts(修正後・抜粋)
import type { PageServerLoad, Actions } from './$types';
import { fail, redirect } from '@sveltejs/kit';
import type { Todo } from '$lib/todo';  // 追加

// type Todo = { ... } の定義はここから削除

let todos: Todo[] = [
  { id: 1, title: '牛乳を買う' },
  { id: 2, title: '本を読む' },
];

import type について

import type { Todo } from '$lib/todo';

import type は型だけをimportする書き方です。コンパイル後のJavaScriptには含まれず、TypeScriptの型チェックにのみ使われます。型情報だけが必要な場合はこの書き方が適切です。

まとめ

概念 内容
src/lib/ 共通データ・型・ユーティリティを置くフォルダ
$lib エイリアス src/lib/ への絶対パス参照(階層を問わず同じ書き方)
export type 型を外部に公開する
import type 型だけをimportする(実行時コードに含まれない)

データや型を $lib に集約することで、変更が1ファイルで完結し、修正漏れを防げます。アプリが大きくなるほど効果が出てくる整理方法です。

← トップページに戻る