Expo + Supabase + NativeWind + Resendのセットアップ
ExpoにSupabaseを導入
基本的に公式Doc通り進めれば問題ない。
パッケージをインストール
$ npx expo install @supabase/supabase-js @react-native-async-storage/async-storage react-native-elements react-native-url-polyfill
AsyncStorageでのsession管理のセットアップ
lib/supabase.ts
を作成する
import 'react-native-url-polyfill/auto'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
})
Expo routerを導入
パッケージをインストール。
$ npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar react-native-gesture-handler
package.jsonを修正
- "main": "node_modules/expo/AppEntry.js",
+ "main": "expo-router/entry",
app.jsonを修正
SupabaseでのDeep Linkに対応するためにschemeは"com.supabase"
を指定する。
{
"expo": {
"name": "Sample App",
"slug": "sample-app",
+ "scheme": "com.supabase",
schemeを指定したら、SupabaseのAuth Settingsの画面からリダイレクトURLにcom.supabase://**
を追加する。
FYI: https://supabase.com/docs/guides/auth/native-mobile-deep-linking
babel.config.jsを修正
module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
+ plugins: ["expo-router/babel"],
};
};
キャッシュをクリアして再起動
$ npx expo start -c
ExpoにNativeWindを導入
パッケージをインストール
$ npm install nativewind
$ npm install --dev tailwindcss@3.3.2
[補足] 公式Docではtailwincssのバージョンが指定されておらず、yarn add --dev tailwindcss
となっていたが、これだと"tailwindcss": "^3.3.6",
がインストールされ、アプリ起動時に以下のエラーが発生した(Expo49)
Use process(css).then(cb) to work with async plugins
詳細まで追えていないが、Tailwindcssの方でBreaking changesがあり、それが要因ぽい。
対処法として、上記の通りバージョンを3.3.2
を指定する。
tailwind.config.jsを以下のコマンドで作成
$ npx tailwindcss init
tailwind.config.jsを修正
Tailwindcssを適用するファイルパスを指定する
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
+ "./App.{js,jsx,ts,tsx}",
+ "index.tsx",
+ "./app/**/*.{js,jsx,ts,tsx}",
+ "./components/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
};
"nativewind/babel"
を追加
babel.config.jsのpluginにmodule.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
- plugins: ["expo-router/babel"],
+ plugins: ["expo-router/babel", "nativewind/babel"],
};
};
このままだと<View className='flex-1'>
のようにした時にclassNameで型エラーが発生するので、app.d.tsをルートディレクトリ配下に作成する。
+ /// <reference types="nativewind/types" />
FYI: https://www.nativewind.dev/getting-started/typescript
あとはいつも通りclassをあてていくだけでOK。
<View className="items-center justify-center w-full h-full px-4">
<Input
placeholder="Email"
value={email}
onChangeText={(text) => setEmail(text)}
className="bg-white rounded-md p-4 text-slate-900"
/>
<View>
<TouchableOpacity
disabled={loading}
onPress={() => signUp()}
className="bg-slate-900 text-white rounded-md py-4 px-8 mt-4"
>
<Text className="text-white font-bold text-md">Sign In</Text>
</TouchableOpacity>
</View>
</View>
スタイルが反映されてなければ、Expoサーバーをキャッシュをクリアして再起動する
$ npm expo start -c
サーバーを再起動してもスタイルが反映されてなければ、tailwind.config.js
のファイルパスの設定が正しいか確認すると良いかもしれない。
Resendの導入
Supabaseにもとから組み込まれているメール送信機能は1時間あたり4件という上限が設定されているため、開発時にそれ以上使いたい場合は外部のメール配信サービスと連携し、カスタムSMTPの設定が必要になる。
以前少し使ったことがあるSendGridを検討したが、アカウント開設に1-2日ほどリードタイムがあるので、SupabaseのWebサイトでも紹介されていたResendを試してみる。
[補足] Resendは10,000通/月、100通/月まで無料プランで使える。SendGridは12,000通/月まで無料。
Resendのアカウントを作成し、次のResendのページからSupabaseを連携する。
連携ボタンを押す。
権限付与をするorgを選択する。
選択したorgの中のどのプロジェクトと連携するかを設定する。
次にAdd an API Keyでドメインを選択するのだが、このドメインは取得済みのカスタムドメインを登録する必要があるっぽく、まだドメインを取得していない段階では使えない...?
Resend自体はカスタムドメインを使わずとも標準の@resend.dev
が利用可能っぽいが、上記のSupabaseとの連携画面ではそれが選択できなさそうだったので困った。
Resend連携の続き
上記のようにResendのIntegrationから設定を進めるとカスタムドメインが必要になるので、別の方法で進めたらカスタムドメインなしで連携ができた。
APIキーを作成する(Resend側)
Resendの方でまずAPIキーを発行する。
APIキーの名前はわかりやすいもので適当でOK。
APIキーは閉じたら再表示はできないので控えておく(1)。
SMTPの設定をする(Supabase側)
Settings > Authentication > SMTP Settingsに進み、Enable Custom SMTPをオンにする。
各フィールドを埋めて登録する。
- Sender email:
{任意の文字列}@resend.dev
- Sender name: 任意の文字列
- Host:
smtp.resend.com
- Port number:
465
- Minimum interval between emails being sent:
1
- Username:
resend
- Password: (1)で発行したAPIキー
これで登録すれば、SupabaseでのAuthで送信されるメールが{任意の文字列}@resend.dev
から送信される🎉
メール認証
Supabaseが提供しているワンタイムパスワードを試してみる
async function signUp() {
setLoading(true);
const { error } = await supabase.auth.signInWithOtp({
email,
});
if (error) {
Alert.alert(error.message);
setLoading(false);
return;
}
setLoading(false);
router.push({
pathname: "/opt",
params: { email },
});
}
メールアドレスを入力して送信すると...
先程連携したSMTPからOTPが送信される。
Resendのダッシュボード
こんな感じのサイバー感のあるUIでログが確認できる。
Resendはキャリアドメイン宛に送信がうまく行かないという話もあるので、Productionへの導入はそのあたりを調査した上で検討だが、一旦SendGridのアカウント開設を待つ間にサクッとローカルでのメール配信環境を作るのには気楽にできていいかなと思った。