nuxt.ts(nuxt.js+Typescript)でfirebaseをインジェクションしたい。

#前書き
　nuxt.jsとFirebaseの組み合わせでなにか作るというのは結構ポピュラーらしく、qiitaでも検索するといろいろな記事が出てきます。私も大変お世話になりました。
　nuxt.jsでFirebaseSDKを使う場合、多くはpluginディレクトリ内でfirebase.jsを用意してFirebase SDKを初期化し、各々のVueファイル内でimportするというのが定番のようです。
　一方でnuxt.jsのインジェクションという機能を使うことで、いちいちvueファイル内でimportせずにFirebaseを呼び出せるようにする方法もあります。importの方がどこで何を使っているのか明示されてわかりやすいのですが、私は横着なのでインジェクションを使っています。
　今回はそれをTypeScript導入済みのnuxt.jsでやってみようと思い、（警告が出ていますが）実際に動作させることができましたので、嬉しさのあまり記事にした次第です。

#やること
TypeScript導入済みのnuxt.jsでFirebaseSDKをインジェクションする。

##省略すること
- nuxt.jsの基本的な情報
- nuxt.jsにTypeScriptを導入する方法
- Firebaseの導入方法

##諦めたこと
- ~~厳密な型付け~~ 

困ったらanyでもいいって偉い人類が言ってた。
([TypeScript再入門 ― 「がんばらないTypeScript」で、JavaScriptを“柔らかい”静的型付き言語に #エンジニアHub - エンジニアHub｜若手Webエンジニアのキャリアを考える！](https://employment.en-japan.com/engineerhub/entry/2019/04/16/103000)
けどやっぱり型がついている方が圧倒的に便利

- 全部TypeScriptにする。

できるところから頑張る。

#各ファイル
基本的には[公式ドキュメント](https://typescript.nuxtjs.org/ja/)に従う形で書けば問題ない。
もっと良い方法があればコメントください。

##plugins/firebase.ts
```typescript:firebase.ts
import firebase from 'firebase/app'
import 'firebase/firestore'
import 'firebase/auth'
import 'firebase/storage'
import 'firebase/messaging'
import 'firebase/analytics'
import { Plugin } from '@nuxt/types' //まずこれが必要

// 親の顔より見た初期化
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig)
}

// FCMに対応していない場合は$messagingはnullにしてエラーを防ぐ。
const messaging: firebase.messaging.Messaging | null = firebase.messaging.isSupported()
  ? firebase.messaging()
  : null

declare module 'vue/types/vue' {
  interface Vue {
    $firebase: firebase.app.App
    $auth: firebase.auth.Auth
    $db: firebase.firestore.Firestore
    $storage: firebase.storage.Storage
    $messaging: firebase.messaging.Messaging | null
    $analytics: firebase.analytics.Analytics
  }
}

declare module '@nuxt/types' {
  interface NuxtAppOptions {
    $firebase: firebase.app.App
    $auth: firebase.auth.Auth
    $db: firebase.firestore.Firestore
    $storage: firebase.storage.Storage
    $messaging: firebase.messaging.Messaging | null
    $analytics: firebase.analytics.Analytics
  }
}

declare module 'vuex/types/index' {
  interface Store<S> {
    $firebase: firebase.app.App
    $auth: firebase.auth.Auth
    $db: firebase.firestore.Firestore
    $storage: firebase.storage.Storage
    $messaging: firebase.messaging.Messaging | null
    $analytics: firebase.analytics.Analytics
}}
// ここでインジェクション
const myPlugin: Plugin = (context, inject) => {
  inject('firebase', firebase)
  inject('auth', firebase.auth())
  inject('db', firebase.firestore())
  inject('storage', firebase.storage())
}

// 普通にexportもできる。初期化済みのfirebaseを別ファイルから呼びたいときはこちら
export default myPlugin
export { firebase, messaging }
export const auth: firebase.auth.Auth = firebase.auth()
export const db: firebase.firestore.Firestore = firebase.firestore()
export const storage: firebase.storage.Storage = firebase.storage()
export const analytics: firebase.analytics.Analytics = firebase.analytics()
export const timestamp: Function = (): firebase.firestore.FieldValue => {
  return firebase.firestore.FieldValue.serverTimestamp()

```
今回は認証機能をmiddlewareに持たせるため、context.appから呼び出せるようにインジェクションする。
##nuxt.config.js
```javascript:nuxt.config.js
 plugins: [ 
     { src: '~/plugins/firebase.ts', mode: 'client' } |
   ], 
```
そのうちTypeScriptにします。

##pages/index.vue
```html:index.vue
 <script lang="ts"> //lang="ts"が必要
 import Vue from 'vue'
 
 type LocalData = { 
   msg: String; 
 };
 export default Vue.extend({ 
   data (): LocalData { 
     return { 
       msg: 'ebi kani uni' 
     } 
   }, 
   created ():void{ 
     const user = this.$auth.currentUser //this.$authで認証機能を呼べる。 
     if (user) { 
       this.$router.push('/brazil') 
     } else { 
       this.$router.push('/exit') 
     } 
   } 
 }) 
 </script> 
```

ここで実際に呼びだす。

##middleware/auth.js
```typescript:auth.ts
 import { Middleware } from '@nuxt/types' // これが必要

 const defaultAuth: Middleware = (context) => { 
   const auth = context.app.$auth 
   auth.onAuthStateChanged((user: any) => { 
     if (!user) { 
       context.redirect('/exit') 
     } 
   } 
   ) 
 } 
  
 export default defaultAuth 
```
asyncDataやmiddlewareで呼び出す場合はこのような書き方。context.appである点に注意。


#参考資料
[Nuxt TypeScript](https://typescript.nuxtjs.org/ja/)

#今までお世話になった記事
[[初心者向け]ゼロから始めるNuxt.js入門](https://qiita.com/Kentaro91011/items/406d8121775f98ddd84d)
[【v2対応】Nuxt.jsとFirebaseを組み合わせて爆速でWebアプリケーションを構築する](https://qiita.com/potato4d/items/cfddeb8732fec63cb29c)
[Vue.js+Firebase Authenticationで認証画面を爆速実装！｜ 開発者ブログ ｜ 株式会社アイソルート](https://www.isoroot.jp/blog/2451/)
[nuxt.js + Firebaseでアプリを作る際に `import firebase ~~ `を毎回書きたくない](https://qiita.com/tomochan/items/03f4dcb7b5021b7fe64f)