Next.jsにFirebase Analyticsを組み込む

# 環境

- [Next.js](https://nextjs.org/) 14.0.1

# 考慮すべきこと

- Firebase Analytics (Google Analytics) はブラウザ環境で実行する必要があるが、Next.js 13 から Server Component がデフォルトになったため、明示的に Client Component で実行する必要がある。
- 明示的にイベントを取得するだけでなく、[自動収集イベント](https://support.google.com/analytics/answer/9322688?hl=ja)も取得するようにする。

# 前提

Firebase 上の設定は済んでおり、Firebase Analytics (Google Analytics) が使えるようになっている。

# 設定

## インストール

```sh
yarn add firebase
```

or

```sh
npm install firebase
```

## config（環境変数）の設定

Firebase の dashboard から、以下の config を取得して、`.env` 等に設定する。

```.env
NEXT_PUBLIC_FIREBASE_API_KEY=TBD
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=TBD
NEXT_PUBLIC_FIREBASE_DATABASE_URL=TBD
NEXT_PUBLIC_FIREBASE_PROJECT_ID=TBD
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=TBD
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=TBD
NEXT_PUBLIC_FIREBASE_APP_ID=TBD
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=TBD
```

## config（環境変数）の読み込み、及び Firebase の初期化

```ts:src/lib/firebase.ts
import { getAnalytics } from 'firebase/analytics'
import { getApps, initializeApp } from 'firebase/app'

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
}

const app = !getApps().length ? initializeApp(firebaseConfig) : getApps()[0]
const analytics =
  process.env.NODE_ENV === 'production' && typeof window !== 'undefined'
    ? getAnalytics(app)
    : undefined

export { analytics }
```

- `app` は複数回呼ばれても、一度だけ initialize されるようにしている。
- `analytics` は `NODE_ENV` と `typeof window` の判定をしている。

## react hooks (useAnalytics) を作成し、Client Component でのみ実行されることを保証する。

```ts:src/hooks/use-analytics.ts
import { analytics } from '@/lib/firebase'
import { logEvent } from 'firebase/analytics'

export const EventName = {
  webLogin: 'web_login',
  webLogout: 'web_logout',
}

export const useAnalytics = (eventName: keyof typeof EventName) => {
  return (eventParams = {}) => {
    if (!analytics) return

    logEvent(analytics, EventName[eventName], eventParams)
  }
}

```

## イベントを送信する

作成した `useAnalytics` を使って、イベントを送信します。

```tsx
'use client'

import { useAnalytics } from '@/hooks/use-analytics'

const Foo = () => {
  const logSomeEvent = useAnalytics('someEvent')

  const handleClick = () => {
    logSomeEvent({ someParam: 'someParam' })
  }

  return (
    <>
     :
          onClick={handleClick}
    </>
  )
}
```

## [自動収集イベント](https://support.google.com/analytics/answer/9322688?hl=ja) を取得するため、root layout（src/app/layout.tsx） で Analytics の initialize を実行する。

これがなくても、イベントを送信したタイミングでログイン情報は取得されますが、ユーザがランディングページを開いた時に、アクティブ・ユーザーとして記録されない。
逆にこの設定をすることで、イベントを送信しなくても、ページを開いたタイミングでアクティブ・ユーザとして記録されるようになる。

```tsx:src/components/common/firebase-analytics.tsx
'use client'
// This component is to initialize Firebase Anaytics (in a client component).
// And it is supposed to be used in src/app/layout.tsx.
//
// You can still send an event without it.
// And the user will be tracked as soon as they send an event.
// However, active users (in real time) will not be tracked without it before they send an event.
import { analytics } from '@/lib/firebase'

analytics

const FirebaseAnalytics = () => {
  // dummy JSX component
  return <div></div>
}

export default FirebaseAnalytics
```

```tsx:src/app/layout.tsx
:
:
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ja">
      <body className={inter.className}>
        <FirebaseAnalytics />
        :
        :
      </body>
    </html>
  )
}
```

# 参考

- https://firebase.google.com/docs/web/setup?sdk_version=v9?hl=ja
- https://firebase.google.com/docs/analytics/get-started?platform=web&hl=ja
```
Google アナリティクスは、ウェブアプリの使用状況や動作に関するデータを収集します。この SDK は主に次の 2 種類の情報を記録します。

イベント: ユーザーの操作、システム イベント、エラーなど、アプリで起こっていること。

ユーザー プロパティ: 言語や地理的位置など、ユーザー層を示す属性。自由に定義できます。

アナリティクスでは、一部のイベントとユーザー プロパティが自動的にロギングされます。こうしたロギングを有効にするコードを追加する必要はありません。
```

- https://support.google.com/analytics/answer/9322688?hl=ja