VercelにホスティングしたNext.jsでFirebase Authenticationを使うベストプラクティス

こんな人におすすめ

- コンポーネントでログインを判別して表示を分けるには？
- コードにAPI Keyとかベタガキしたくない、簡単な方法は？

> 今回、数時間ハマった。次回迷わないようにメモしておく。
> もっといい方法あったら教えてください

# コンポーネントまわり
> 参考：https://firebase.google.com/docs/auth/web/manage-users?hl=ja

## `pages/index.js`に以下を貼り付ける

```js

import * as firebase from "firebase/app";
import "firebase/auth";
import { useState } from 'react'

const firebaseConfig = {
  apiKey: process.env.FIREBASE_API_KEY,
  authDomain: process.env.FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.FIREBASE_DATABASE_URL,
  projectId: process.env.FIREBASE_PROJECT_ID,
  storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.FIREBASE_APP_ID,
  measurementId: process.env.FIREBASE_MEASUREMENT_ID
};
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig)
}

export default function SignInOut() {
  const [user, setUser] = useState(undefined)
  firebase.auth().onAuthStateChanged((user) => { user ? setUser(user) : setUser(undefined) });

  function signInWithTwitter() {
    const provider = new firebase.auth.TwitterAuthProvider();
    firebase.auth().signInWithPopup(provider).catch(function (error) {
      console.log(error.code, error.message)
    });
  }

  function signOut() {
    firebase.auth().signOut().catch(function (error) {
      console.log(error.code, error.message)
    })
  }

  function SignInOutButton() {
    return user ?
      <button onClick={signOut}>SignOut</button> :
      <button onClick={signInWithTwitter}>SignIn</button>

  }

  return <SignInOutButton />
}

```

### 簡単な解説
- firebaseのドキュメントを読むと、onAuthStateChangedを使えとは書いてあるが、それをどう使えばログインを判別できるのかがわからなかった。
- 結論、onAuthStateChangednの中でstateをsetする処理を書けばOKらしい。
- コンポーネント側からはそのstateをみて、だし分けてやれば良い。
- ログインとログアウトのhandleでstateをsetしてしまうと、コンポーネント側に反映されないので注意...


# 環境変数まわり
> 参考：https://nextjs.org/docs/basic-features/environment-variables

## `.env.local`に環境変数を定義する

```bash
FIREBASE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
FIREBASE_AUTH_DOMAIN=xxxxxxxxxxxxx.firebaseapp.com
FIREBASE_DATABASE_URL=https://xxxxxxxxxxxxx.firebaseio.com
FIREBASE_PROJECT_ID=xxxxxxxxxxxxx
FIREBASE_STORAGE_BUCKET=xxxxxxxxxxxxx.appspot.com
FIREBASE_MESSAGING_SENDER_ID=xxxxxxxxxxxxx
FIREBASE_APP_ID=1:xxxxxxxxxxxxx:web:xxxxxxxxxxxxxxxxxxx
FIREBASE_MEASUREMENT_ID=x-xxxxxxxxxxxxx
```

> こいつをgitで管理してしまうと、わるい人にfirebaseアカウントを使われてしまうので、しっかりと`.gitignore`に追加しておく

## vercelで環境変数を定義する
GUIでぽちぽち入力していく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131737/24eaa389-f596-fcd2-edbe-4d10359b99b2.png)

> vercel CLI を使って、ここからローカルに環境変数をpullしてくる方法でも良いかも

## `next.config.js`に以下を貼り付ける

```js
module.exports = {
    env: {
        FIREBASE_API_KEY: process.env.FIREBASE_API_KEY,
        FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN,
        FIREBASE_DATABASE_URL: process.env.FIREBASE_DATABASE_URL,
        FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
        FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET,
        FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID,
        FIREBASE_APP_ID: process.env.FIREBASE_APP_ID,
        FIREBASE_MEASUREMENT_ID: process.env.FIREBASE_MEASUREMENT_ID,
    }
}
```
# その他
ローカルではログインログアウトが正常に動作していたのに、デプロイしたら動かない...
## firebase Authentication の設定でvercelのドメインを許可
firebaseのコンソールから、Authentication > Sign-In Method > 承認済みドメイン と進んで、そこにvercelによってデプロイされたドメイン(xxx.vercel.app など)を追加する

コレを忘れると、開発者ツールのコンソールになんかエラーが出て、正常に処理されない。