作成したアプリケーション
Next.js & Firebase を利用した学習用のサンプルアプリケーションです。
Firebase Auth を利用したログイン/ログアウト、会員登録機能 に対応しています。
また、投稿データの取得・更新は、Cloud Functions 経由で、Cloud Firestore に永続化されるようにしています。
デモ
主な機能
- ログイン/ログアウト
- 会員登録
- 投稿一覧
- 投稿詳細
- マイページ(一覧・登録・更新・削除)
プロジェクトの概要
ローカルの開発環境では、DockerでFirebaseのエミュレータを起動して接続できるようにしています。
Firebaseのエミュレータ は、Auth ・ FireStore ・ Functions ・Hosting のような各種サービスが1つのエミュレータに纏まっていて非常に開発者にとって便利なツールになっています。
利用している技術
- Next.js (React16)
- Redux Tool Kit
- Typescript
- Firebase Auth
- Firebase FireStore
- Firebase Functions
Firebase Auth を利用した認証方法
firebase とのIO に必要な設定や共通処理は utilities/firebase.ts
に纏めるようにしました。環境変数でローカルの場合のみDockerのエミュレータと通信されるようにしています。
utilities/firebase.ts
import firebase from 'firebase/compat/app'
import 'firebase/compat/auth'
import 'firebase/compat/firestore'
import 'firebase/compat/functions'
const isEmulator = () => {
const useEmulator = process.env.NEXT_PUBLIC_USE_FIREBASE_EMULATOR
return !!(useEmulator && useEmulator === 'true')
}
const config = {
apiKey: process.env.FIREBASE_KEY,
authDomain: process.env.FIREBASE_DOMAIN,
databeseURL: process.env.FIREBASE_DATABASE,
projectId: process.env.FIREBASE_PROJECT_ID,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.FIREBASE_SENDER_ID,
appId: process.env.FIREBASE_APPID,
}
export const getApp = () => {
if (!firebase.apps.length) {
firebase.initializeApp(config)
if (isEmulator()) {
firebase.firestore().useEmulator('localhost', 8080)
firebase.functions().useEmulator('localhost', 5001)
firebase.auth().useEmulator('<http://localhost:9099>')
}
} else {
firebase.app()
}
return firebase
}
export const getFirestore = () => {
return getApp().firestore()
}
export const getFunctions = () => {
const region = isEmulator() ? undefined : 'asia-northeast1'
return getApp().functions(region)
}
export const getAuth = () => {
return getApp().auth()
}
.env
FIREBASE_KEY="xxxxxx"
FIREBASE_DOMAIN="xxxxxx"
FIREBASE_DATABASE="xxxxxx"
FIREBASE_PROJECT_ID="xxxxxx"
FIREBASE_STORAGE_BUCKET="xxxxxx"
FIREBASE_SENDER_ID="xxxxxx"
FIREBASE_APPID="xxxxxx"
NEXT_PUBLIC_USE_FIREBASE_EMULATOR=true
Firebase Auth
ログイン
const onSubmit = async (values) => {
const { email, password } = values
try {
await getAuth().signInWithEmailAndPassword(email, password)
router.push(URL.HOME)
} catch (err) {
alert(err.message)
}
}
ログアウト
getAuth().signOut()
認証チェック
auth/AuthProvider.tsx
import React, { FC, createContext, useEffect, useState, ReactNode } from 'react'
import { User } from 'firebase'
import { getAuth } from '../utilities/firebase'
type AuthContextProps = {
currentUser: User | null | undefined
}
const AuthContext = createContext<AuthContextProps>({ currentUser: undefined })
type Props = {
children?: ReactNode
}
const AuthProvider: FC = ({ children }: Props) => {
const [nowLoading, setNowLoading] = useState<boolean>(true)
const [currentUser, setCurrentUser] = useState<User | null | undefined>(
undefined
)
useEffect(() => {
getAuth().onAuthStateChanged((user) => {
setCurrentUser(user)
setNowLoading(false)
})
}, [])
return nowLoading ? (
<div>Loading...</div>
) : (
<AuthContext.Provider value={{ currentUser }}>
{children}
</AuthContext.Provider>
)
}
export { AuthContext, AuthProvider }
import { AuthContext } from '@/auth/AuthProvider'
const MemberPostsList: FC = () => {
const router = useRouter()
const auth = useContext(AuthContext)
const user = auth.currentUser
if (!user) {
// 未ログイン時はログイン画面を表示させる
router.push('/login')
return <></>
}
・・・・
}
開発環境の構築
ソースコード
MIT ライセンスにてコードを公開していますのでご利用下さいませ。
https://github.com/isystk/nextjs-typescript-firebase
ディレクトリ構造
.
├── docker/
│ ├── apache/ (Webサーバー)
│ │ └── Dockerfile
│ ├── app/ (Node.js をDockerで動作させたい場合に利用する)
│ │ └── Dockerfile
│ └── firebase/ (Firebase のエミュレータ)
│ ├── Dockerfile
│ └── src
│ └── functions (Cloud functions のソースコード)
├── public/
├── src/ (Next.js のソースコード)
│ ├── auth/
│ ├── common/
│ ├── components/
│ ├── pages/
│ ├── store/
│ ├── styles/
│ └── utilities/
├── test/
└── dc.sh (Dockerの起動用スクリプト)
操作用シェルスクリプトの使い方
Usage:
dc.sh [command] [<options>]
Options:
stats|st Dockerコンテナの状態を表示します。
init Dockerコンテナ・イメージ・生成ファイルの状態を初期化します。
start すべてのDaemonを起動します。
stop すべてのDaemonを停止します。
firebase login Firebase にログインします。
firebase start Firebase のエミュレータを起動します。
firebase build Cloud Functions をビルドします。
firebase deploy Firebase にデプロイします。
--version, -v バージョンを表示します。
--help, -h ヘルプを表示します。
起動方法
# 下準備
$ ./dc.sh init
$ cp .env.example .env
# Dockerを起動する
$ ./dc.sh start
# 初回のみFirebaseのセットアップ
./dc.sh firebase login
./dc.sh firebase init
# Firebaseエミュレータを起動します。
$ ./dc.sh firebase start
$ open <http://localhost:4000>
# Cloud Functions をビルドします。
docker-compose -f docker/docker-compose.yml exec firebase sh
cd ./functions
yarn
yarn build
# 投稿データをPOST
curl -X POST -H "Content-Type: application/json" -d @post.json <http://localhost:5001/nextjs-typescript-firestore/us-central1/api/posts>
# 投稿データの一覧を取得する
curl <http://localhost:5001/nextjs-typescript-firestore/us-central1/api/posts>
# Next.jsアプリを起動します。
./dc.sh app install
./dc.sh app dev
$ open <http://localhost:3000>
# Dockerを停止する場合
$ ./dc.sh stop