※この記事はQiita(Firebase Javascript SDK v8→v9 のCloud FireStore取扱書 in Nuxt × TypeScript)にも投稿されているものです。
はじめに
8月下旬、Firebase JavaScript SDK v9がリリースされました。
自分のポートフォリオサイトはFirebaseを利用していたのでv9へアップデートしたのですが、記法に互換性がなくなっていた影響で素直にアップデートするだけではダメでした。
そこで、v8, v9それぞれの記法の違いを簡単にまとめようと思います。
その際に遭遇した型エラーもこちらへ残します。
※ 今回はCloud FireStoreに触れます
対象者
- Nuxt.jsでFirebaseのFireStoreを利用している方
- Firebase Javascript SDK v8 → v9にアップデートしたい方
- FireStoreに型を付けたい方
- 🐭 !!🐮 !!🐯 🐰 🐲 🐍 🐴 🐏 🐵 🐔 🐶 🐗
筆者の環境
- Node.js (14.18.0)
- yarn (1.22.4)
- Firebase (9.1.3)
- TypeScript (4.2.4)
- VScode(1.60.0)
- Nuxtは2系です
まずはFirebase初期化部分から
■ v8 SDK
Firebase JavaScript SDK v8の詳しい導入方法はこちらに記載されています。
公式が「v9 SDK を使用することを強くおすすめします。」と言っているので特別な理由がない限りは、v9を利用した方がいいみたいです。
// v8
import firebase from 'firebase/app';
if (!firebase.apps.length) {
firebase.initializeApp({/* config */});
}
export default firebase;
上記補足として、以下のエラーが発生することがあったので
Firebase: Firebase App named '[DEFAULT]' already exists
対処として
if (!firebase.apps.length) {
...
}
で囲ってエラー回避していました。
■ v9 SDK
import 周りが変わっています。
利用するやつのみ import することによってコンパイル時のアプリサイズを削減できるのが売りらしいです。
📦新しいモジュラーJavaScriptSDKは、アプリバンドルを最大80%小さくすることができますJavaScript SDKのバージョン9は、バンドラーが未使用のコードを排除し、JavaScriptバンドルのFirebaseライブラリコードを最大80%削減できるモジュールファーストフォーマットを採用しています。
configに型が用意されていたので早速使っています。
// 必要なもののみimport
import { FirebaseOptions, getApps, getApp, initializeApp, FirebaseApp } from 'firebase/app';
const firebaseConfig: FirebaseOptions = {/* config */};
const firebase: FirebaseApp = !getApps().length ? initializeApp(firebaseConfig) : getApp();
export default firebase;
v8の時に発生したエラーはv9では !getApps().length
を利用した分岐で回避するようにしました。
Cloud FireStoreを利用する側
ここでは、データ取得, データ追加周り v8 と v9 の時の記法をそれぞれご紹介します。
必要な部分のみ抜粋しています。
■ データ取得
はじめにデータ取得の実装周りです。
取得部分は今回 created
内に書いていますが、あくまで記事用なので created
内に書く特別な意図はありません。
□ v8 SDK
firebase/firestore はまるまるimportしています。
// v8
<script lang="ts">
import firebase from '~/plugins/firebase';
import 'firebase/firestore';
export default Vue.extend({
created () {
const db: firebase.firestore.Firestore = firebase.firestore(); // Firestore のインスタンスを初期化
if (!db) { return; }
db.collection('hoge').get()
.then((querySnapshot) => {
querySnapshot.forEach((doc: firebase.firestore.QueryDocumentSnapshot) => {
...
});
});
}
})
□ v9 SDK
firestoreは必要な部分のみimportするようになりました。
記法が変わり、 getDocs
という取得用の新しい関数が登場しました。
また、型定義も変わっています。
// v9
<script lang="ts">
import firebase from '~/plugins/firebase';
import { Firestore, getFirestore, getDocs, collection, QueryDocumentSnapshot } from 'firebase/firestore';
export default Vue.extend({
created () {
const db: Firestore = getFirestore(firebaseApp); // Firestore のインスタンスを初期化
if (!db) { return; }
getDocs(collection(db, 'hoge'))
.then((querySnapshot) => {
querySnapshot.forEach((doc: QueryDocumentSnapshot) => {
...
});
});
}
})
■ データ追加
続いてデータ追加の実装周りです。
□ v8 SDK
// v8
<script lang="ts">
import firebase from '~/plugins/firebase';
import 'firebase/firestore';
export default Vue.extend({
methods: {
addData () {
const db: Firestore = getFirestore(firebaseApp);
db.collection("hoge").add({
name: "deren",
country: "Japan"
});
}
}
})
□ v9 SDK
こちらも記法が変わり、 addDoc
というデータ追加用の新しい関数が登場しました。
// v9
<script lang="ts">
import firebase from '~/plugins/firebase';
import { Firestore, getFirestore, addDoc, collection } from 'firebase/firestore';
export default Vue.extend({
methods: {
addData () {
const db: Firestore = getFirestore(firebaseApp);
await addDoc(collection(db, 'hoge'), {
name: 'deren',
country: 'Japan'
});
}
}
})
v8 → v9にアップデートした際の型エラー
互換性がなくなった影響で、v8 → v9 へアップデートした際に型エラーがちらほら発生しました。
以下に記載する私が遭遇したエラーはこの記事で解消できるものなので、似たようなエラーに遭遇してしまったらこの記事を参考にしていただけると嬉しいです。
■ Cannot find namespace 'firebase'
// v8
const db: firebase.firestore.Firestore = firebase.firestore();
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// v9
const db: Firestore = getFirestore(firebaseApp);
※ 型は firebase/firestore
から importしてください
■ Property 'firestore' does not exist on type 'FirebaseApp'
// v8
const db: firebase.firestore.Firestore = firebase.firestore();
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// v9
const db: Firestore = getFirestore(firebaseApp);
※ 型は firebase/firestore
から importしてください
■ Parameter 'querySnapshot' implicitly has an 'any' type.
// v8
await this.db.collection('hoge').get()
.then((querySnapshot) => {
querySnapshot.forEach((doc: firebase.firestore.QueryDocumentSnapshot) => {
...
});
})
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// v9
await getDocs(collection(this.db, 'hoge'))
.then((querySnapshot) => {
querySnapshot.forEach((doc: QueryDocumentSnapshot) => {
...
});
})
※ 型は firebase/firestore
から importしてください