|
2 | 2 |
|
3 | 3 | Intended to be run with Angular 12, AngularFire 7.0 allows you to take full advtange of the new tree-shakable Firebase JS SDK (v9) while also providing a compatible expirience with the prior API.
|
4 | 4 |
|
5 |
| -**TBD** |
| 5 | +## Compatibility mode |
| 6 | + |
| 7 | +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/*`. |
| 8 | + |
| 9 | +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. |
| 10 | + |
| 11 | +## Modular SDK |
| 12 | + |
| 13 | +### Initialization |
| 14 | + |
| 15 | +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. |
| 16 | + |
| 17 | +**Before:** |
| 18 | +```ts |
| 19 | +@NgModule({ |
| 20 | + imports: [ |
| 21 | + AngularFire.initalizeApp(config), |
| 22 | + AngularFirestoreModule.enablePersistence({ synchronizeTabs: true }), |
| 23 | + AngularFireStorageModule, |
| 24 | + ], |
| 25 | + providers: [ |
| 26 | + { provide: SETTINGS, useValue: { ignoreUndefinedProperties: true } }, |
| 27 | + { provide: USE_EMULATOR, useValue: ['localhost', 8080] }, |
| 28 | + ], |
| 29 | +}) |
| 30 | +``` |
| 31 | + |
| 32 | +**Modular SDK:** |
| 33 | +```ts |
| 34 | +@NgModule({ |
| 35 | + imports: [ |
| 36 | + provideFirebaseApp(() => initializeApp(config)), |
| 37 | + provideFirestore(() => { |
| 38 | + const firestore = getFirestore(); |
| 39 | + connectEmulator(firestore, 'localhost', 8080); |
| 40 | + enableIndexedDbPersistence(firestore); |
| 41 | + return firestore; |
| 42 | + }), |
| 43 | + provideStorage(() => getStorage()), |
| 44 | + ], |
| 45 | + providers: [ |
| 46 | + { provide: FIRESTORE_SETTINGS, useValue: { ignoreUndefinedProperties: true } }, |
| 47 | + ], |
| 48 | +}) |
| 49 | +``` |
| 50 | + |
| 51 | +### Injecting services |
| 52 | + |
| 53 | +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. |
| 54 | + |
| 55 | +```ts |
| 56 | +import { FirebaseApp } from '@angular/fire'; |
| 57 | +import { Firestore } from '@angular/fire/firestore'; |
| 58 | +import { doc, onSnapshot } from 'firebase/firestore'; |
| 59 | + |
| 60 | +@Component({}) |
| 61 | +export class Foo { |
| 62 | + constructor( |
| 63 | + app: FirebaseApp, |
| 64 | + firestore: Firestore, // Injects the instantiated Firestore instance |
| 65 | + ) { |
| 66 | + // You can directly operate on the instance with the JS SDK |
| 67 | + // NOTE: you will have to handle change-detection yourself |
| 68 | + onSnapshot(doc(firestore, 'foo/1'), snap => { |
| 69 | + // ... |
| 70 | + }); |
| 71 | + } |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +### Class methods |
| 76 | + |
| 77 | +AngularFire no longer provides observables and functions as class methods, everthing is a implemented as a pure function that can be tree-shaken. |
| 78 | + |
| 79 | +<table> |
| 80 | + <thead> |
| 81 | + <tr> |
| 82 | + <th colspan="2">v6 / Compat</th> |
| 83 | + <th>v7 Modular</th> |
| 84 | + </tr> |
| 85 | + </thead> |
| 86 | + <tbody> |
| 87 | + <tr> |
| 88 | + <td rowspan="3">AngularFirestore</td> |
| 89 | + <td>collection</td> |
| 90 | + <td class="highlight highlight-source-ts"><pre>import { collection } from 'firebase/firestore'</pre></td> |
| 91 | + </tr> |
| 92 | + <tr> |
| 93 | + <td>doc</td> |
| 94 | + <td><code>import { doc } from 'firebase/firestore'</code></td> |
| 95 | + </tr> |
| 96 | + <tr> |
| 97 | + <td>collectionGroup</td> |
| 98 | + <td><code>import { doc } from 'firebase/firestore'</code></td> |
| 99 | + </tr> |
| 100 | + </tbody> |
| 101 | +</table> |
| 102 | + |
| 103 | +### Code splitting and lazy-loading |
| 104 | + |
| 105 | +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 |
| 106 | + |
| 107 | +```ts |
| 108 | +// firestore_operations.ts |
| 109 | +import { collection, getFirestore } from 'firebase/firestore'; |
| 110 | +import { collectionData, firestoreInstance$ } from '@angular/fire/firestore'; |
| 111 | +import { first } from 'rxjs/operators'; |
| 112 | + |
| 113 | +export { getFirestore }; |
| 114 | + |
| 115 | +export const fooData = firestoreInstance$.pipe( |
| 116 | + first(), |
| 117 | + concatMap(firestore => collectionData<IFoo>(collection(firestore, 'foo'))), |
| 118 | +); |
| 119 | +``` |
| 120 | + |
| 121 | +```ts |
| 122 | +export class AuthService { |
| 123 | + constructor() { |
| 124 | + getRedirectResult().then(result => { |
| 125 | + // Initialize Firestore only after a user logs in |
| 126 | + if (result.user) { |
| 127 | + const { getFirestore } = await import('./firestore_operations'); |
| 128 | + getFirestore(); |
| 129 | + } |
| 130 | + }); |
| 131 | + } |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | +```ts |
| 136 | +@Component({}) |
| 137 | +export class Foo { |
| 138 | + data: Observable<IFoo[]>; |
| 139 | + constructor() { |
| 140 | + this.data = of(undefined).pipe( |
| 141 | + concatMap(() => import('./firestore_operations')), |
| 142 | + concatMap(it => it.fooData) |
| 143 | + ); |
| 144 | + } |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +### Working with multiple apps / instances |
| 149 | + |
| 150 | +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. |
| 151 | + |
| 152 | +```ts |
| 153 | +@NgModule({ |
| 154 | + imports: [ |
| 155 | + provideFirebaseApp(() => initializeApp(config)), |
| 156 | + provideFirebaseApp(() => initializeApp(config2, 'anotherApp')), |
| 157 | + provideStorage(() => getStorage(getApp())), |
| 158 | + provideStorage(() => getStorage(getApp(), 'another bucket')), |
| 159 | + provideStorage(() => getStorage(getApp('anotherApp'))), |
| 160 | + ], |
| 161 | + providers: [ |
| 162 | + { provide: FIRESTORE_SETTINGS, useValue: { ignoreUndefinedProperties: true } }, |
| 163 | + ], |
| 164 | +}) |
| 165 | +``` |
| 166 | + |
| 167 | +```ts |
| 168 | +import { FirebaseApp, FirebaseApps } from '@angular/fire/app'; |
| 169 | +import { Storage, StorageIsntances } from '@angular/fire/storage'; |
| 170 | + |
| 171 | +export class Foo { |
| 172 | + constructor( |
| 173 | + defaultApp: FirebaseApp, // Injects the default FirebaseApp |
| 174 | + firebaseApps: FirebaseApps, // Injects an array of all initialized Firebase Apps |
| 175 | + storage: Storage, // Injects the default FirebaseApp's default storage instance |
| 176 | + storageInstances: StorageInstances, // Injects an array of all the intialized storage instances |
| 177 | + ) { } |
| 178 | +} |
| 179 | +``` |
| 180 | +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. |
0 commit comments