Firebase を利用して Next.js でWebアプリケーションを作成する

作成したアプリケーション

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

コメントを残す

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。