Firebase JavaScript SDK v9 + Authentication で認証を実装する

Firebase JavaScript SDK が、v9で大きく変わりました。 バージョンアップに伴い、Authenticationの実装の仕方もかなり変わったため、メモを残しておきます。

## Firebase JavaScript SDK v9 の仕様

v9では、SDKの中から必要なモジュールだけを読み込んで利用する「Tree Shaking」という手法を採用しています。webpackなどで採用されている手法です。

https://firebase.googleblog.com/2021/08/the-new-firebase-js-sdk-now-ga.html


## JavaScript SDK v9 を利用した認証の実装

今回の変更を踏まえて、Firebase Authenticationの認証を実装してみました。

### ディレクトリ構成

今回のサンプルはこんな構成で作成しました。

```bash
├── dist
│   ├── bundle.js
│   └── index.html
├── firebase.json
├── node_modules
├── package-lock.json
├── package.json
├── src
│   └── index.js
└── webpack.config.js
```

srcディレクトリ配下のindex.js がエントリーポイント。
dist/bundle.js が、SDKのモジュールをロード後、出力したJSファイルとなります。

以下、各種ファイルの記述

webpack.config.js

```javascript
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  devtool: 'eval-source-map',
};
```

package.json

```javascript
{
  "name": "auth-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --mode=development"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "firebase": "^9.6.6"
  },
  "devDependencies": {
    "webpack": "^5.68.0",
    "webpack-cli": "^4.9.2"
  }
}
```

firebase.json
今回は「dist」が公開ディレクトリになるよう設定しました。

```bash
{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}
```


index.jsはこんな感じに書いてみました。
今回は、Googleアカウントを利用した認証のみ許可しています。

```javascript
import { initializeApp } from "firebase/app";

const firebaseConfig = {

/* 
Firebaseから Config を取得して書き込みます
*/

};

const app = initializeApp(firebaseConfig);

import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

const auth = getAuth();
const provider = new GoogleAuthProvider();

window.signIn = function() {
    signInWithPopup(auth, provider)
    .then((result) => {
      const credential = GoogleAuthProvider.credentialFromResult(result);
      const token = credential.accessToken;
      // The signed-in user info.
      const user = result.user;
      // ...
    }).catch((error) => {
      // Handle Errors here.
      const errorCode = error.code;
      const errorMessage = error.message;
      const email = error.email;
      const credential = GoogleAuthProvider.credentialFromError(error);
      // ...
    });
    }
  
window.signOut = function() {
    auth.onAuthStateChanged(user => {
        auth.signOut()
        .then(() => {
          console.log('ログアウトしました');
          location.reload();
        })
        .catch((error) => {
          console.log(`ログアウト時にエラーが発生しました (${error})`);
        });
    });
    }
  
   auth.onAuthStateChanged(user => {
      if (user) {
          const signOutMessage = `
          <p>Hello, ${user.displayName}!<\/p>
          <button class="btn btn-primary" type="submit"  onClick="signOut()">サインアウト<\/button>
          `;
          document.getElementById('auth').innerHTML =  signOutMessage;
          console.log('ログインしています');
  
      } else {
            const signInMessage = `
            <button class="btn btn-primary" type="submit"  onClick="signIn()">サインイン<\/button>
            `;
            document.getElementById('auth').innerHTML = signInMessage;       
      }
    });
  
```

index.html
webpackで出力した「bundle.js」をロードしています。

```html
<!DOCTYPE html>
<html lang="ja">

<head>
  <title>Firebase Authentication WebPack</title>
  <script src="bundle.js"></script>
</head>

<body>
  <h1>Firebase Authentication WebPack</h1>
  <div id="auth"></div>
</body>
</html>
```


設定が終わったら、webpackでJSファイルを出力します。

```bash
npm run build
```

出力後、動作確認。意図通り動作しました。

![スクリーンショット 2022-02-13 16.59.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83767/5e2ab911-7298-5ed5-93e0-0c7b802c669b.png)


## 参考ドキュメント

Firebase JavaScript SDK v9 と webpack の組み合わせについては、下記のドキュメントが詳しかったです。これを読めば大体理解できると思います。

https://firebase.google.com/docs/web/module-bundling