SvelteKit + Prisma + Supabaseで開発できる環境をセットアップする

# はじめに
SvelteKitは昨年12月にバージョン1.0に到達しました！ 

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

今後、Webアプリケーションを作っていく選択肢の1つとしてと`SvelteKit`を使って開発していくというのはありだと思っています。
`SvelteKit`に`Prisma`と`Supabase`を組み合わせた開発というのは鉄板の構成の1つになりそうなのでセットアップ方法を紹介します！

# SvelteKitの初期設定

SvelteKitの新規プロジェクトをCLIを使って作成します。

```bash
$ npm create svelte@latest sveltekit-prisma-supabase
```

今回はTypeScriptを使用する前提で記事を書いていきますので`TypeScript`のみ選択しました。
他に、`ESLint`,`Prettier`,`Playwright`,`Vitest`を使用するか選択することができます！
今回の記事では言及しませんが、使用したい場合は選択しましょう。

```bash
create-svelte version 2.3.1

Welcome to SvelteKit!

✔ Which Svelte app template? › Skeleton project
✔ Add type checking with TypeScript? › Yes, using TypeScript syntax
✔ Add ESLint for code linting? … No
✔ Add Prettier for code formatting? … No
✔ Add Playwright for browser testing? … No
✔ Add Vitest for unit testing? … No
```

```bash
$ cd sveltekit-prisma-supabase
$ npm install
$ npm run dev
```

`http://localhost:5173/`にアクセスし、`Welcome to SvelteKit`の画面が表示されたらSvelteKitのセットアップは完了です。
![スクリーンショット 2023-01-24 16.21.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/112565e6-6500-8244-0c12-e560c1d54eaf.png)

# Supabaseの初期設定
Supabaseを利用するにはGitHubアカウントでログインするか、アカウント登録が必要なのでどちらかを選んでログインしましょう。

https://app.supabase.com/sign-in

`new project`でプロジェクトを作成します。
プロジェクトの名前とデータベースのパスワードを設定して、リージョンは特別理由がない限りは、`Northeast Asia(Tokyo)`を選択するといいと思います。 料金プランは`Free`を選択します。


![スクリーンショット 2023-01-24 16.26.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/b4052f70-eb6c-c11a-0b61-ec3e882e5cb6.png)

# シャドウデータベースを作成する

**この問題はissueが立っているので今後解消されて、シャドウデータベースを作成する必要がなくなる可能性があります。**

https://github.com/prisma/prisma/issues/17160

Prismaのマイグレーションはpostgresデータベースを削除しようする影響で、Supabaseデータベースとの競合を引き起こす可能性があります。その回避策として今回は、[Prisma Shadow Databases](https://www.prisma.io/docs/concepts/components/prisma-migrate/shadow-database#cloud-hosted-shadow-databases-must-be-created-manually)を使用する為、シャドウデータベースを作成します。

![スクリーンショット 2023-01-24 16.55.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/0c759fc9-16f4-8b26-fecd-1a8905a3210d.png)

`Settings` -> `Database` -> `Connection String` -> `PSQL`の文字列をコピーして、`psql CLI`を使って接続します。

```bash
$ psql -h db.[YOUR-PROJECT-REF].supabase.co -p 5432 -d postgres -U postgres
```

接続できたら、データベースを作成します。

```bash
postgres=> CREATE DATABASE postgres_shadow;
postgres=> exit;
```

これでシャドウデータベースの作成は完了です。

# Prismaの初期設定
まずは必要なパッケージをインストールします。
```bash
$ npm install prisma --save-dev
$ npm install @prisma/client
```

次に、prismaのセットアップをします。

```bash
$ npx prisma init
```

実行すると`prisma/schema.prisma`と`.env`が自動的に作成されると思いますので、次はこれらのファイルを編集していきます。

# DBのマイグレーション
`prisma/schema.prisma`に以下のようなスキーマを定義します。
モデルは今回適当に用意したものを使います。

```prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  Int?
}
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}
```

`.env`は以下のように定義します。
`[YOUR-PASSWORD]`と`[YOUR-PROJECT-REF]`は適宜書き換えてください。
```.env
DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:5432/postgres"
SHADOW_DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-REF].supabase.co:5432/postgres_shadow"
```

最後にPrismaのマイグレーションコマンドを実行します。

```bash
$ npx prisma migrate dev --name init
```

Supabaseのダッシュボードの `Database` -> `Tables`を確認するとスキーマ定義どおりにテーブルが作成されているのがわかります。

![スクリーンショット 2023-01-24 17.12.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/3a5a250d-6a3f-8d8b-7061-c54adc5182d0.png)

# SvelteKit + Prismaを使ってデータ取得、表示

`src/lib/server/prisma.ts`を作成します。
SvelteKitではファイル名に`.server`をつけるか`src/lib/server`内にファイルを置くことでサーバーでのみ実行できるように制限することができます。

https://kit.svelte.jp/docs/server-only-modules

```ts:src/lib/server/prisma.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default prisma;
```

まずはデータを取得します。`src/routes/+page.server.ts`を作成します。
Prismaの`findMany()`を使って`user`テーブルから複数のレコードを取得して返します。
```ts:src/routes/+page.server.ts
import prisma from '$lib/server/prisma';
import type { PageServerLoad } from './$types';

export const load = (async () => {
	return {
		users: await prisma.user.findMany()
	};
}) satisfies PageServerLoad;
```

次に、このままだとDBのuserテーブルが空で何も表示できないのでSupabaseの`Table Editor` -> `Insert row`からいくつかデータを追加しておきましょう。

![スクリーンショット 2023-01-24 17.39.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/33930ebf-9da3-e929-caa2-46df70b4ebc5.png)

最後に出力側です。`src/routes/+page.svelte`を編集します。
`+page.server.ts`で取得して返したデータが`data`に格納されているので`data`から`users`を取り出して表示させてみます。

```html:src/routes/+page.svelte
<script lang="ts">
  import type { PageData } from './$types';

  export let data: PageData;
  const { users } = data;
</script>

<ul>
  {#each users as user}
    <li>id: {user.id}</li>
    <li>email: {user.email}</li>
    <li>name: {user.name}</li>
  {/each}
</ul>
```

`Supabase`のDBに接続し、`SvelteKit` + `Prisma`を使ってデータを取得、表示することができました！
![スクリーンショット 2023-01-24 17.44.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/6efc3e3f-252a-3af2-aa24-afcd478318f8.png)

# おわりに
すごく簡単に`SvelteKit` + `Prisma` + `Supabase`で開発できる環境をセットアップすることができました！
これからSvelteKitで開発してみたいよという方は是非参考にしてみてください！