DartでSupabase Edge Functionsを作成してローカルで実行する手順(2024年2月版)

# 概要

https://supabase.com/docs/guides/functions/dart-edge

https://dartling.dev/full-stack-dart-with-flutter-supabase-and-dart-edge

これらのサイトに書かれている手順は現状と異なっており上手く行かないので自分用に手順をまとめてみる

# インストール・準備

:::note
supabase CLIの実行にはnode.jsとnpm(またはbun)が、
supabase本体の実行にはdocker及びdocker-composeが、
edge CLIのインストールにはflutter sdkまたはdart sdkが必要ですが
流石にこれらのインストール手順は省略
:::

### supabase CLIの実行

supabaseのインストールというか実行にはnpxを使います。npmでグローバルインストールは出来ないようです。
というわけで以降の手順ではnpxを通じてsupabaseコマンドを使います。
他の方法でインストールしてsupabaseコマンドが直接使える場合はnpxを省略してください

```
npx supabase <command>
```

### edge CLIのインストール

pubコマンドを使ってグローバルインストールします。

```
dart pub global activate edge
```

# supabaseの初期化

supabase CLIのinitコマンドでsupabase環境の初期化をします。

```
npx supabase init
```

概要のサイトの手順ではfunctionを作成した後にsupabase initするように書かれていますが、そうすると関数ごとに新しくsupabase環境を作ることになるのでしてはいけません。

この記事では、適当に`c:¥dartfunc¥`フォルダでsupabase initしたという想定で記述します。

# edge functionsの作成

この記事では適当に`c:¥dartfunc¥functions`フォルダ内にedge functionsを作っていく想定で記述します

```
edge new supabase_functions testfunc
```
`Create project in C:\dartfunc\functions\testfunc?(Y/n)`とプロジェクトを作成するか聞かれるので`y`を入力してください。
後はedgeが作成したフォルダに移動してpub getで必要なdartモジュールをインストールします。
```
cd testfunc
dart pub get
```

# edge.yamlの作成

https://github.com/invertase/dart_edge/issues/52?utm_source=pocket_saves

https://github.com/invertase/dart_edge/blob/main/docs/platform/supabase/config.mdx


コンパイルしたedge functionは`<supabase initしたフォルダ>¥supabase¥functions¥<関数名>¥`フォルダにファイルがないと登録しても実行してくれません。

概要のサイトの手順ではedge function作成後のフォルダでsupabase initすることによってファイル移動の手順を省いたのかもしれませんが、このままedge CLIでコンパイルすると`<edge CLIが作成したフォルダ>¥functions¥dart_edge¥`フォルダにコンパイル結果を生成してしまい、supabaseが想定する`supabase¥functions¥<関数名>`とは異なるので概要のサイトの手順通りに実行しても動きません。

コンパイルしたファイルを手動で移動しないですむように`edge.yaml`(.ymlではダメです!!)でコンパイル結果の生成先を設定することが出来ます。
また、`edge.yaml`なしの場合、関数名は`dart_edge`、エントリポイントのdartファイルは`lib¥main.dart`に固定されてしまい関数も複数作ることができませんが、これらも`edge.yaml`で設定することによって解決出来ます。

```yaml:edge.yamlの例
supabase:
  #関数名とその関数のエントリーポイント(main関数)があるdartファイルを指定。複数指定も可能。
  functions:
    test: "lib/main.dart"
    test2: "lib/main2.dart"

  #supabase initしたフォルダ内のsupabaseフォルダを指定(絶対パス、相対パスどっちでもOK)
  project_path: "c:/dartfunc/supabase"
```

このファイルを今回の例では`c:¥dartfunc¥functions¥testfunc`フォルダ内に作成して編集します。

```edge.yaml
supabase:
  functions:
    test: "lib/main.dart"

  project_path: "c:/dartfunc/supabase"
```

# コンパイル

:::note warn
これは2024年2月時点の情報です。将来的には状況が異なっている可能性が極めて高いです。
:::

https://github.com/invertase/dart_edge/issues/50?utm_source=pocket_saves

2024年2月現在のDart最新版(3.2.6)ではdart-edgeによるedge関数のコンパイル(JavaScriptへの変換)は上手くいきません。js相互運用の仕様が変わっているのですがdart-edgeがそれに追従出来ていないのが原因です。
今のところ追従するまではfvmを利用して古いバージョンのDart(今回はFlutter 3.7.12→Dart 2.19.6を利用)でコンパイルするしかないようです。

### fvmのインストール

```
dart pub global activate fvm
```

### 旧バージョンのdartを適用

edge newしたフォルダ(今回の記事では`c:¥dartfunc¥functions¥testfunc`)で実行します

```
fvm use 3.7.12 -f
```

### 旧バージョンのdartでコンパイル

```
fvm dart run edge build supabase_functions
```

:::note
### 上記の問題が解決済みの場合は

もし、将来的に上記の問題が解決していた場合は以下のコマンドでコンパイルします。

```
edge build supabase_functions
```
:::

# edge functionの登録

edge functionを作成したらsupabaseに登録する必要があります。
登録するためにはsupabaseが動いている必要があるので、まだ動かしていない場合は`supabase init`したフォルダで`supabase start`を実行してsupabaseを動かします。

```
npx supabase start --ignore-health-check
```

```
npx supabase functions serve test --no-verify-jwt
```

edge functionはデフォルトでは認証ヘッダの設定が求められるので、テスト用途などそういった処理が面倒な場合は`--no-verify-jwt`フラグを付けて登録することで認証ヘッダの設定を回避することが出来ます。

`<supabase initしたフォルダ>¥supabase¥functions¥<関数名>`にファイルがないと登録しても動きませんが、登録時点では存在していなくてもエラーにはしないのでわかりにくいです。気をつけましょう。

# 実行

localhostでsupabaseを動かしている場合は

`http://localhost:54321/functions/v1/<関数名>`

にブラウザでアクセスすると実行して結果がブラウザに返ってきます。登録に失敗して関数が存在しない場合は`Function not found`というメッセージが返ってきます。