PlanetScale を触ってみたいと思っていたので、簡易的なアプリを作成しました。
Vite、preact、も以前から気になっていたので、参考になれば嬉しいです。
構成
- ビルドツール
- vite
- データベース
- PlanetScale
- サーバ
- Netlify
- アプリケーション
- preact, Typescript, Prisma
始める前に結論
- 無料枠が大きいので個人開発で遊ぶのにも十分だと思う
- UXが最高。ほとんどのプログラマーがgithubユーザーだと思うので、直感的に操作することが可能
- mysqlで抱えていた、本番DBと開発DBの情報に差分が発生して意図しないバグを生じてしまう問題を上手く解決してくれそう(上記に記載したように、githubのようなユーザー体験が提供されているためschema変更の
revart
なんかも可能)
始める前の準備
PlanetScale と Netlify はそれぞれ cli が用意されているのでインストールしておく
npm install netlify-cli -g
netlify // インストールされているか確認
⬥ Netlify CLI
Read the docs: https://www.netlify.com/docs/cli
Support and bugs: https://github.com/netlify/cli/issues
VERSION
netlify-cli/9.16.6 darwin-x64 node-v14.17.0
Vite プロジェクト作成
適当なディレクトリを作成
mkdir ディレクトリ名
cd ディレクトリ名
npm init vite@latest .
プロジェクト名等々、何を利用するか問われるので以下の項目を入力・選択
npm init vite@latest
npx: 6個のパッケージを3.977秒でインストールしました。
✔ Project name: … プロジェクト名
✔ Select a framework: › preact
✔ Select a variant: › preact-ts
cd プロジェクト名
npm i
プロジェクト作成完了
ローカルサーバを走らせる
netlify dev
◈ Netlify Dev ◈
◈ Ignored general context env var: LANG (defined in process)
◈ Starting Netlify Dev with Vite
┌─────────────────────────────────────────────────┐
│ │
│ ◈ Server now ready on http://localhost:8888 │
│ │
└─────────────────────────────────────────────────┘
補足: netlify dev
コマンドに関しては以下を参照
Run the entire Netlify platform right from your terminal
http://localhost:8888
でプロジェクトが正常に立ち上がっているか確認
PlanetScale の設定
補足: PlanetScale のアカウントをまだ作成していなければ、以下を参照
PlanetScaleというサーバレスDBが凄く勢いのあるサービスらしいのでQuick Startやってみた
pscale cli 取得
$ npm i scale -g
$ which sclae
ターミナルから PlanetScale へ login
$ pscale auth login
Confirmation Code: ここに認証用コードが表示される
ブラウザで planetscale 認証ページが自動で開かれるので、ターミナル上に出力される認証用コードと一致しているか確認。問題なければブラウザ上に表示されている、「Confirme code」ボタンをクリック
開発用ブランチを作成する
$ pscale branch create データベース名 dev // devは任意のブランチ名
shadowブランチを作成する
※ このブランチはPrismaのmigrations用に使われる
$ pscale branch create データベース名 shadow // devは任意のブランチ名
正常に上記設定が行われているか確認
ローカルからデータベースへ接続
$ pscale connect データベース名 dev[ブランチ名] --port 3309
$ pscale connect データベース名 shadow[ブランチ名] --port 3310
エディタで本プロジェクトコードを展開して.env
ファイルを追加
追加した.env
ファイルに以下記述
DATABASE_URL="mysql://root@127.0.0.1:3309/データベース名"
SHADOW_DATABASE_URL="mysql://root@127.0.0.1:3310/データベース名"
Prisma の設定
prisma をプロジェクトに追加
npm i -D prisma
npm i @prisma/client
schemaファイルを生成
npx prisma init
schema.prisma
を以下のように修正
generator client {
provider = "prisma-client-js"
previewFeatures = ["referentialIntegrity"]
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
referentialIntegrity = "prisma"
}
アプリ用モデルをschema.prisma
に追加する
generator client {
provider = "prisma-client-js"
previewFeatures = ["referentialIntegrity"]
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
referentialIntegrity = "prisma"
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
title String @db.VarChar(255)
content String
}
上記で定義した schema を基にテーブルを作成
$ npx prisma migrate dev
新しいマイグレーション name を入力
Enter a name for the new migration: ... init
試験用データをテーブルに追加する
$ npx prisma studio
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Prisma Studio is up on http://localhost:5555
ブラウザでhttp://localhost:5555
を開く
schema ファイルを基に prisma client を生成
$ Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
✔ Generated Prisma Client (3.12.0 | library) to ./node_modules/@prisma/client in 70ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
npx prisma generate
コマンドはスキーマを取得し、typescript定義を持つprismaクライアントを作成して、データベースとのやり取りに必要なものを自動で準備してくれる
serverless functionを定義
プロジェクトのルートディレクトリにnetlify/functions/posts.ts
を作成する.
ファイル内は以下のような構成.
処理の内容は post した情報をDBから取得して返すだけのシンプルなもの.
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export async function handler() {
try {
const posts = await prisma.post.findMany();
return {
statusCode: 200,
header: {
'Content-Type': 'application/json',
},
body: JSON.stringify(posts),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify(error),
};
}
}
ちなみに、Netlify の Netlify function とは Netlify が提供しているアドオンの1つで、サーバーサイドの機能を簡単に公開できるサービスです。AWS Lambda をラップして使いやすいように提供されており、 AWSにアカウントを用意する必要もありません。NetlifyのプロジェクトとGitリポジトリを連携するだけでOK。Netlifyが代わりにデプロイをしてくれる上に、HTTPで呼び出せる機能がすぐに用意できる代物。
上記コードが正常に機能するかテストする
ローカルサーバを起動(もし起動していなければ)
$ netlify dev
◈ Netlify Dev ◈
◈ Ignored build settings env var: DATABASE_URL (defined in .env file)
◈ Injected .env file env var: DATABASE_URL
◈ Ignored general context env var: LANG (defined in process)
◈ Injected .env file env var: SHADOW_DATABASE_URL
◈ Loaded function post.
◈ Loaded function posts.
◈ Functions server is listening on 62987
◈ Starting Netlify Dev with Vite
> prisma-serverless@0.0.0 dev /Users/ryoma_kishimoto/Desktop/prisma-serverless-planetscale-netlify/prisma-serverless
> vite
vite v2.9.5 dev server running at:
> Local: http://localhost:3000/
> Network: use `--host` to expose
ready in 540ms.
┌─────────────────────────────────────────────────┐
│ │
│ ◈ Server now ready on http://localhost:8888 │
│ │
└─────────────────────────────────────────────────┘
posts を返すか確認
http://localhost:8888/.netlify/functions/posts
次は実際にデータを post する処理をプロジェクトのルートディレクトリ(netlify/functions/post.ts
)に作成する.
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export async function handler(event) {
const { title, content } = JSON.parse(event.body);
try {
await prisma.post.create({
data: { title, content },
});
return {
statusCode: 200,
body: 'post created',
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify(error),
};
}
}
正常に起動するか確認する
VSCodeの拡張機能でThunder Client
という優れものがあるので、おすすめです.
https://www.thunderclient.com/
ブラウザからのPOST機能実装
以下のコードをそのままsrc/app.tsx
へcopy & paste
しちゃってOK
import { useState, useEffect } from 'preact/hooks';
type Post = {
id: number;
title: string;
content: string;
createdAt: Date;
updatedAt: Date;
};
export function App() {
const [loadPosts, setLoadPost] = useState(true);
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [posts, setPosts] = useState([]);
useEffect(() => {
async function load() {
if (!loadPosts) {
return;
}
const allPosts = await fetch('/.netlify/functions/posts').then((res) =>
res.json()
);
setPosts(allPosts);
setLoadPost(false);
}
load();
}, [loadPosts]);
async function handleSubmit(event: any) {
event.preventDefault();
await fetch('/.netlify/functions/post', {
method: 'POST',
body: JSON.stringify({ title, content }),
});
setTitle('');
setContent('');
setLoadPost(true);
}
return (
<>
<h1>投稿画面</h1>
<ul>
{posts.map((post: Post) => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>Created {new Date(post.createdAt).toLocaleString()}</p>
<p>Updated {new Date(post.updatedAt).toLocaleString()}</p>
</li>
))}
</ul>
<h2>投稿しよう</h2>
<form onSubmit={handleSubmit}>
<label htmlFor='title'>Title</label>
<input
type='text'
id='title'
name='title'
value={title}
onChange={(e) => setTitle((e.target as HTMLInputElement).value)}
/>
<label htmlFor='content'>content</label>
<input
type='content'
id='content'
name='content'
value={content}
onChange={(e) => setContent((e.target as HTMLInputElement).value)}
/>
<button type='submit'>Save</button>
</form>
</>
);
}
一応、cssも記述.
html,
body {
font-family: 'Helvetica Neue', arial, sans-serif;
}
button,
label {
display: block;
margin-top: 1rem;
}
以下画面がブラウザ上で確認できるはずなので正常に「投稿→投稿されたPOSTが表示」されるか挙動チェック
PlanetScaleのProduction環境DBの準備
PlanetScale のコンソール画面上からmain
ブランチを選択
main
ブランチをproduction
用としてpromote
任意のブランチをmain
ブランチにdeploy
するために、deploy request
を上げる.(git
のpull request
に近いイメージ)
ターミナルから以下コマンドを叩く
pscale deploy-request create データベース名 dev // devは任意のブランチ名
PlanetScaleのコンソール画面上にある、「Deploy requests」を選択すると、deploy request
が確認できる
summary
タブから「Add changes to deploy queue」ボタンをクリック
Netlifyへアプリケーションをデプロイ
丁寧にまとめられている、以下記事を参考にして下さい
https://qiita.com/suin/items/743fe6252ad8af425c5e
「Site settings」をクリックし、画面左に表示されている「Build & deploy」タブを選択
「Build settings」項目で以下のように設定し、下部の「save」ボタンをクリック
PlanetScaleからDBへのURLを取得する
コンソール画面上の「overview」タブを選択し、画面右の「connect」ボタンをクリック
「connect with」ドロップダウンメニューから「Prisma」を選択し、画面右のコピーアイコンをクリックしたら適当なメモ帳等にペーストしておく
Netlifyへ戻り、「Site settings」をクリック、画面左に表示されている「Build & deploy」タブを選択して、以下スクショのように設定(value
には先ほどコピペした、DATABASE_URL情報のここから→mysql://~
をペーストする)
これで終了. もし正常にdeployされていない場合は、「Deploy」タブから「Trigger deploy」ボタンをクリックして再度、deployを行なって下さい。