@angular/fire
Version:
The official Angular library for Firebase.
299 lines (250 loc) • 8.49 kB
Markdown
# Upgrading to AngularFire 7.0
Intended to be run with Angular 12, AngularFire 7.0 allows you to take full advantage of the new tree-shakable Firebase JS SDK (v9) while also providing a compatible experience with the prior API.
`ng update @angular/fire`
## Breaking changes
* Angular 12 is required
* AngularFire now only works in Ivy applications
* Firebase JS SDK v9 is required
* The existing AngularFire v6 API surface has moved from `@angular/fire/*` to `@angular/fire/compat/*` (see compatibility mode)
* **compat/auth:** `USE_EMULATOR` DI token is now in the form of `['http://localhost:9099']`
## Compatibility mode
AngularFire v7.0 has a compatibility layer that supports the AngularFire v6.0 API. Just change your imports from `@angular/fire/*` to `@angular/fire/compat/*` and `firebase/*` to `firebase/compat/*`.
While not as tree-shakable as the new modular SDK, this allows you to upgrade and take advantage of the benefits of the new SDK ASAP.
**Most developers can stop here for now as the new API isn't feature complete.**
## **NEW** Modular SDK
### Initialization
In order to better support the tree-shakability introduced in Firebase v9 & to reduce the maintence required when the JS SDK adds new configuration flags, AngularFire providers now take a factory for a fully instantiated instance of the SDK you'd like to inject.
**Before:**
```ts
@NgModule({
imports: [
AngularFireModule.initializeApp(config),
AngularFirestoreModule.enablePersistence(),
AngularFireStorageModule,
],
providers: [
{ provide: USE_EMULATOR, useValue: ['localhost', 8080] },
],
})
```
**Modular SDK:**
```ts
@NgModule({
imports: [
provideFirebaseApp(() => initializeApp(config)),
provideFirestore(() => {
const firestore = getFirestore();
connectFirestoreEmulator(firestore, 'localhost', 8080);
enableIndexedDbPersistence(firestore);
return firestore;
}),
provideStorage(() => getStorage()),
],
})
```
### Injecting services
Before when you injected Firebase JS SDK services into AngularFire they would be lazy-loaded and a promise-proxy would be returned to you. In AngularFire v7 you get the intiated service directly. We no longer lazy load for you.
```ts
import { Firestore, doc, onSnapshot, DocumentReference, docSnapshots } from '@angular/fire/firestore';
@Component({})
export class Foo {
doc: DocumentReference;
constructor(
firestore: Firestore, // Injects the instantiated Firestore instance
) {
// You can directly operate on the instance with JS SDK methods which we've
// reexported in AngularFire
this.doc = doc(firestore, 'foo/1');
onSnapshot(doc, snap => {
// ...
});
// or use the convenience observables
docSnapshots(doc).subscribe(...);
}
async update() {
await updateDoc(this.doc, { ... });
...
}
}
```
### Working with multiple apps / instances
In AngularFire v7 working with multiple instances was difficult, in the new SDK we have new DI tokens that make working with them much more straight forward.
```ts
@NgModule({
imports: [
provideFirebaseApp(() => initializeApp(config)),
provideFirebaseApp(() => initializeApp(config2, 'anotherApp')),
provideStorage(() => getStorage()),
provideStorage(() => getStorage(getApp(), 'anotherBucket')),
provideStorage(() => getStorage(getApp('anotherApp'))),
],
})
```
```ts
import { FirebaseApp, FirebaseApps } from '@angular/fire/app';
import { Storage, StorageInstances } from '@angular/fire/storage';
export class Foo {
constructor(
defaultApp: FirebaseApp, // Injects the default FirebaseApp
allFirebaseApps: FirebaseApps, // Injects an array of all initialized Firebase Apps
storage: Storage, // Injects the default storage instance
allStorageInstances: StorageInstances, // Injects an array of all the intialized storage instances
) { }
}
```
How the main injection tokens (i.e, `FirebaseApp`, `Storage`) function have changed from v7 but it should provide a much more powerful and intuitive API.
### API
Beyond Depdency Injection AngularFire is sporting an entirely new API:
1) We no longer handle lazy-loading the Firebase JS SDK modules for you
1) We no longer provide classes beyond Depedency Injection
1) No more Proxy / Promise-Proxy
1) We reexport and Zone-wrap all Firebase and RxFire APIs
So developing with the new AngularFire is easy, you can use it just like the vanilla Firebase JS SDK. Just change all your `firebase/app` imports to `@angular/fire/app`, `firebase/firestore` to `@angular/fire/firestore`, `firebase/database` to `@angular/fire/database`, etc. Then if you're feeling comfortable with RXJS and would like to use some of our convenience operators you can just dip into that toolbox.
#### Alternatives to v6 APIs
<table>
<thead>
<tr>
<th colspan="2">v6 / Compat</th>
<th>v7 Modular</th>
</tr>
</thead>
<tbody>
<tr>
<th rowspan="3">AngularFirestore</th>
<td>doc</td>
<td>
```ts
import { doc } from '@angular/fire/firestore';
doc<T>(firestore, 'foo/bar') // DocumentReference<T>
```
</td>
</tr>
<tr>
<td>collection</td>
<td>
```ts
import { collection } from '@angular/fire/firestore';
collection<T>(firestore, 'foo') // CollectionReference<T>
```
</td>
</tr>
<tr>
<td>collectionGroup</td>
<td>
```ts
import { collectionGroup } from '@angular/fire/firestore';
collectionGroup<T>(firestore, 'foo') // Query<T>
```
</td>
</tr>
<tr>
<th rowspan="7">AngularFirestoreDocument</th>
<td>set</td>
<td>
```ts
import { setDoc } from '@angular/fire/firestore';
setDoc(docRef, { ... }) // Promise<void>
```
</td>
</td>
</tr>
<tr>
<td>update</td>
<td>
```ts
import { updateDoc } from '@angular/fire/firestore';
updateDoc(docRef, { ... }) // Promise<void>
```
</td>
</tr>
<tr>
<td>delete</td>
<td>
```ts
import { deleteDoc } from '@angular/fire/firestore';
deleteDoc(docRef) // Promise<void>
```
</td>
</tr>
<tr>
<td>collection</td>
<td>
```ts
import { collection } from '@angular/fire/firestore';
collection<T>(docRef, 'bar') // CollectionReference<T>
```
</td>
</tr>
<tr>
<td>snapshotChanges</td>
<td>
```ts
import { docSnapshots } from '@angular/fire/firestore';
docSnapshots<T>(docRef) // Observable<DocumentSnapshot<T>>
```
</td>
</td>
</tr>
<tr>
<td>valueChanges</td>
<td>
```ts
import { docData } from '@angular/fire/firestore';
docData<T>(docRef) // Observable<T>
```
</td>
</tr>
<tr>
<td>get</td>
<td>
```ts
import { getDoc } from '@angular/fire/firestore';
getDoc<T>(docRef) // Promise<DocumentSnapshot<T>>
```
</td>
</tr>
</tbody>
</table>
### Code splitting and lazy-loading
AngularFire does not lazy-load services any longer. We have provided a helper observable for detecting when a new service instance is instantiated. In this example we'll code split out of all the Firestore related code and lazy-load
```ts
// firestore_operations.ts
import {
collectionData,
firestoreInstance$,
collection,
getFirestore
} from '@angular/fire/firestore';
import { first } from 'rxjs/operators';
import { IFoo } from '../interfaces';
export { getFirestore };
export const fooData = firestoreInstance$.pipe(
first(),
concatMap(firestore => collectionData<IFoo>(collection(firestore, 'foo'))),
);
```
```ts
export class AuthService {
constructor() {
getRedirectResult().then(result => {
// Initialize Firestore only after a user logs in
if (result.user) {
const { getFirestore } = await import('./firestore_operations');
getFirestore();
}
});
}
}
```
```ts
@Component({})
export class Foo {
data: Observable<IFoo[]>;
constructor() {
this.data = of(undefined).pipe(
concatMap(() => import('./firestore_operations')),
concatMap(it => it.fooData)
);
}
}
```