Vercelに構築したNext.js*Supabaseの環境をローカルにも構築する
BaaS便利だけど
Next.jsを書いてみつつ、Supabaseとの連携やVercelでのデプロイについて学んでいます。段階を踏んで勉強していきたい私のような初学者にとって、Supabaseのような無料枠のあるBaaS(Backend as a Service)は非常に便利です。
一方、ローカルですべてが完結する技術に比べると、開発初期の環境構築が少し難しい(イメージしにくい)という弱点もあります。今回は、オンラインのSupabase環境が構築できたと仮定して、ローカルの構築を行っていきます。
前提条件
最小構成のNext.jsアプリをVercelのテンプレートで作成し、Githubに自動でInitial commit、Supabaseと紐づけるところまで完了しました。デプロイURLをクリックするとデモアプリが表示される状態からスタートです。
手順
1. Supabaseのインストール
初っ端から引用で恐縮ですが、npx supabase init
まではこれを参考にやってみました。
↓ 参考にさせていただいた記事
Supabaseをローカル環境に構築してNext.jsアプリで利用する(前半)
紆余曲折をへて初期化まで完了します。
2. Supabaseの起動
次に、Supabaseの起動を試みます。しかし、npx supabase start
を実行しようとするとhealthcheckの段階でerrorが出て停止してしまいます。
supabase_vector_project container is not ready: unhealthy というerrorです。
↓ 参考にさせていただいた記事
意外とネットに情報がないSupabaseの困りごとメモ(2024/10/14現在) - Qiita
根本的な解決策ではないようですが、以下のようにconfig.tomlを編集すればよいとのこと。
[analytics]
- enabled = true
+ enabled = false
port = 54327
backend = "postgres"
⇒ これを行うことで、SupabaseのAPIURLなどが取得できました。
3. テーブルを追加する(オンライン)
次に、Supabaseにテーブルを作成していきます。ここでは試しにメモアプリを作成します。メモ内容を保持する「notes」というテーブルを作成し、以下のような構成とします。
ソースは以下の通り、2つに分けて記載します(クライアントサイドの処理は分離させて書く必要があります)。
// app\page.tsx
import NoteForm from './components/NoteForm';
export default function Home() {
return <NoteForm />;
}
// app\components\NoteForm.tsx
"use client";
import { createClient } from '@supabase/supabase-js';
import { useState } from 'react';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || '';
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '';
const supabase = createClient(supabaseUrl, supabaseAnonKey);
export default function NoteForm() {
const [message, setMessage] = useState('');
const [error, setError] = useState('');
// メモを登録する関数
const addNote = async (content: string) => {
try {
setMessage('');
setError('');
console.log('Supabase URL:', supabaseUrl);
console.log('Adding note with content:', content);
const { data, error } = await supabase
.from('notes')
.insert([{ content }]);
if (error) {
console.error('Error adding note:', error);
setError(`エラー: ${error.message}`);
} else {
console.log('Note added:', data);
setMessage('メモが追加されました!');
}
} catch (e) {
console.error('Exception:', e);
setError(`例外が発生しました: ${e instanceof Error ? e.message : String(e)}`);
}
};
return (
<div className="p-4">
<h1 className="text-xl font-bold mb-4">メモアプリ</h1>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
onClick={() => addNote('新しいメモ')}
>
Add Note
</button>
{message && <p className="mt-2 text-green-600">{message}</p>}
{error && <p className="mt-2 text-red-600">{error}</p>}
</div>
);
}
4. テーブルを追加する(ローカル)
ネット記事には「SQLをエクスポートしてきましょう」との記載。オンライン版のSupabaseには確かにエクスポートボタンはありました。しかし、このままdb push
しても何も起こりません(そりゃそうだ)。
↓ 参考にさせていただいた記事
5分でわかる!Supabase CLIを使いこなすための開発フロー
調べると、ローカルのSupabaseを扱えるGUIの「Supabase Studio」なるものが存在しており、こっちを使うことが明らかになりました。
Supabase studioでテーブルを作成し、
npx supabase db dump --local -f supabase/schema.sql
を実行すると、
schema.sql
の79行目にテーブルの定義が作成されていました。
CREATE TABLE IF NOT EXISTS "public"."notes" (
"id" bigint NOT NULL,
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
"content" "text"
);
続いて、型定義ファイルの作成です。
ルートディレクトリにtypes\supabase.ts
を作成し、
npx supabase gen types typescript --local > types/supabase.ts
を実行しました。
5. テーブルへのアクセス権限
Notesテーブルにアクセス(特にinsert)するためには、あらかじめPolicyの設定を行っておく必要があります。設定はアクションやparamsを指定して行うことができます。
Supabase Studioを開いて、左側のペインから「Authentication」を選択、「CONFIGRATION」からnotesの「Create policy」を選びます。
設定画面の右側に現れるTemplateの「Insert」を選び、「Target roles」を「Default」にすればOKです。改めてnpm run dev
を実行すると、無事にメモアプリが動作するようになりました。
↓ 参考にさせていただいた記事
next.jsとsupabaseでRow Level Securityを使用して権限による抽出をおこなってみた - Qiita
以上の対応をし、無事Noteテーブルにメモ情報を持ったメモアプリができました。
(最後に)デプロイしてみる
メモアプリをVercelでデプロイしてみます。おうち(クラウド)に帰るまでが遠足(ローカル環境構築)です。まずはgitignoreを見直して、環境変数やschema.sqlを追跡から外します。
コミットすると、自動的にデプロイが始まりましたが、エラー。と思ったら、環境変数が入っていないだけでした。慌てて環境変数を入れなおしてredeployすると、無事メモアプリが立ち上がりました。
Discussion