Quickstart: Supabase

Supabase を使ったクイックスタート

はじめに

Supabase はオープンソースの Firebase 代替品です。

このクイックスタートは、Plasmo で Supabase を使用する簡単な例を示しています。

事前準備

Supabase を使用して Plasmo プロジェクトを初期化

pnpm create plasmo --with-supabase

環境変数の設定

Supabase を動作させるには、URL と KEY を定義する必要があります。

これらの情報は、Supabase プロジェクトのダッシュボードで見つけることができます。

.env ファイルにそれらを追加しましょう。

.env
PLASMO_PUBLIC_SUPABASE_URL="CHANGE ME"
PLASMO_PUBLIC_SUPABASE_KEY="CHANGE ME"

Supabase ストア

Supabase を初期化する必要があるため、core/supabase.ts というファイルを追加しましょう。

core/supabase.ts
import { createClient } from "@supabase/supabase-js"
 
import { Storage } from "@plasmohq/storage"
 
const storage = new Storage({
  area: "local"
})
 
export const supabase = createClient(
  process.env.PLASMO_PUBLIC_SUPABASE_URL,
  process.env.PLASMO_PUBLIC_SUPABASE_KEY,
  {
    auth: {
      storage,
      autoRefreshToken: true,
      persistSession: true,
      detectSessionInUrl: true
    }
  }
)

リダイレクト URL の追加

ユーザーがサインアップすると、メールアドレスを確認する必要があります。これを行うには、Supabase プロジェクトにリダイレクト URL を追加する必要があります。

まず、開発用の拡張機能の一貫した ID を作成する必要があります。異なるウェブストアにプッシュすると、異なる ID が取得されます。この仕組みの詳細については、一貫性のある拡張機能IDの作成 (opens in a new tab)に関するブログ投稿をご覧ください。

Itero KeyPair ツール (opens in a new tab) にアクセスして、一貫性のある拡張機能 ID を生成します。

ID と公開鍵を .env ファイルに保存できます。

.env
CRX_ID="Itero KeyPair ツールから取得した CRX ID の値をここに置き換えてください"
CRX_KEY="Itero KeyPair ツールから取得した公開鍵の値をここに置き換えてください"

次に、package.jsonmanifest.key 値で公開鍵を参照します。

"manifest": {
  "host_permissions": [
    "https://*/*"
  ],
  "key": "$CRX_KEY",
}

次に、ブラウザがオプションページへのアクセスをブロックしないようにする必要があります。これを行うには、manifestweb_accessible_resources に追加する必要があります。

"web_accessible_resources": [
  {
    "resources": [
      "options.html"
    ],
    "matches": [
      "<all_urls>"
    ],
    "extension_ids": [
      "$CRX_ID"
    ]
  }
]

Supabase コンソールにアクセスし、「認証」タブをクリックして、URL 設定をクリックします。

次に、サイト URL とリダイレクト URL の両方に次の URL を追加します。

chrome-extension://<CRX_ID>/options.html

CRX_ID を、Itero KeyPairs ツールで提供された生成された拡張機能 ID、または本番 Web ストアで提供された実際の ID に置き換えてください。

React コンポーネントとの統合

これで、React コンポーネントで Supabase を使用したコードを記述できます!

拡張機能のオプションページで Supabase を使用する React コンポーネントの例を以下に示します。

options.tsx
import type { Provider, User } from "@supabase/supabase-js"
import { useEffect, useState } from "react"
 
import { Storage } from "@plasmohq/storage"
import { useStorage } from "@plasmohq/storage/hook"
 
import { supabase } from "~core/supabase"
 
function IndexOptions() {
  const [user, setUser] = useStorage<User>({
    key: "user",
    instance: new Storage({
      area: "local"
    })
  })
 
  const [username, setUsername] = useState("")
  const [password, setPassword] = useState("")
 
  useEffect(() => {
    async function init() {
      const { data, error } = await supabase.auth.getSession()
 
      if (error) {
        console.error(error)
        return
      }
      if (!!data.session) {
        setUser(data.session.user)
      }
    }
 
    init()
  }, [])
 
  const handleEmailLogin = async (
    type: "LOGIN" | "SIGNUP",
    username: string,
    password: string
  ) => {
    try {
      const {
        error,
        data: { user }
      } =
        type === "LOGIN"
          ? await supabase.auth.signInWithPassword({
              email: username,
              password
            })
          : await supabase.auth.signUp({ email: username, password })
 
      if (error) {
        alert("Error with auth: " + error.message)
      } else if (!user) {
        alert("Signup successful, confirmation mail should be sent soon!")
      } else {
        setUser(user)
      }
    } catch (error) {
      console.log("error", error)
      alert(error.error_description || error)
    }
  }
 
  const handleOAuthLogin = async (provider: Provider, scopes = "email") => {
    await supabase.auth.signInWithOAuth({
      provider,
      options: {
        scopes,
        redirectTo: location.href
      }
    })
  }
 
  return (
    <main
      style={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        width: "100%",
        top: 240,
        position: "relative"
      }}>
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          width: 240,
          justifyContent: "space-between",
          gap: 4.2
        }}>
        {user && (
          <>
            <h3>
              {user.email} - {user.id}
            </h3>
            <button
              onClick={() => {
                supabase.auth.signOut()
                setUser(null)
              }}>
              ログアウト
            </button>
          </>
        )}
        {!user && (
          <>
            <label>メールアドレス</label>
            <input
              type="text"
              placeholder="ユーザー名"
              value={username}
              onChange={(e) => setUsername(e.target.value)}
            />
            <label>パスワード</label>
            <input
              type="password"
              placeholder="パスワード"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
            />
 
            <button
              onClick={(e) => {
                handleEmailLogin("SIGNUP", username, password)
              }}>
              サインアップ
            </button>
            <button
              onClick={(e) => {
                handleEmailLogin("LOGIN", username, password)
              }}>
              ログイン
            </button>
 
            <button
              onClick={(e) => {
                handleOAuthLogin("github")
              }}>
              GitHub でサインイン
            </button>
          </>
        )}
      </div>
    </main>
  )
}
 
export default IndexOptions

完全な例

完全な例を見るには、 examples リポジトリにある with-supabase (opens in a new tab) を確認してください!