UNPKG

8.49 kBMarkdownView Raw
1# Upgrading to AngularFire 7.0
2
3Intended 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.
4
5`ng update @angular/fire`
6
7## Breaking changes
8
9* Angular 12 is required
10* AngularFire now only works in Ivy applications
11* Firebase JS SDK v9 is required
12* The existing AngularFire v6 API surface has moved from `@angular/fire/*` to `@angular/fire/compat/*` (see compatibility mode)
13* **compat/auth:** `USE_EMULATOR` DI token is now in the form of `['http://localhost:9099']`
14
15## Compatibility mode
16
17AngularFire 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/*`.
18
19While 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.
20
21**Most developers can stop here for now as the new API isn't feature complete.**
22
23## **NEW** Modular SDK
24
25### Initialization
26
27In 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.
28
29**Before:**
30```ts
31@NgModule({
32 imports: [
33 AngularFireModule.initializeApp(config),
34 AngularFirestoreModule.enablePersistence(),
35 AngularFireStorageModule,
36 ],
37 providers: [
38 { provide: USE_EMULATOR, useValue: ['localhost', 8080] },
39 ],
40})
41```
42
43**Modular SDK:**
44```ts
45@NgModule({
46 imports: [
47 provideFirebaseApp(() => initializeApp(config)),
48 provideFirestore(() => {
49 const firestore = getFirestore();
50 connectFirestoreEmulator(firestore, 'localhost', 8080);
51 enableIndexedDbPersistence(firestore);
52 return firestore;
53 }),
54 provideStorage(() => getStorage()),
55 ],
56})
57```
58
59### Injecting services
60
61Before 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.
62
63```ts
64import { Firestore, doc, onSnapshot, DocumentReference, docSnapshots } from '@angular/fire/firestore';
65
66@Component({})
67export class Foo {
68 doc: DocumentReference;
69 constructor(
70 firestore: Firestore, // Injects the instantiated Firestore instance
71 ) {
72 // You can directly operate on the instance with JS SDK methods which we've
73 // reexported in AngularFire
74 this.doc = doc(firestore, 'foo/1');
75 onSnapshot(doc, snap => {
76 // ...
77 });
78 // or use the convenience observables
79 docSnapshots(doc).subscribe(...);
80 }
81 async update() {
82 await updateDoc(this.doc, { ... });
83 ...
84 }
85}
86```
87
88### Working with multiple apps / instances
89
90In 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.
91
92```ts
93@NgModule({
94 imports: [
95 provideFirebaseApp(() => initializeApp(config)),
96 provideFirebaseApp(() => initializeApp(config2, 'anotherApp')),
97 provideStorage(() => getStorage()),
98 provideStorage(() => getStorage(getApp(), 'anotherBucket')),
99 provideStorage(() => getStorage(getApp('anotherApp'))),
100 ],
101})
102```
103
104```ts
105import { FirebaseApp, FirebaseApps } from '@angular/fire/app';
106import { Storage, StorageInstances } from '@angular/fire/storage';
107
108export class Foo {
109 constructor(
110 defaultApp: FirebaseApp, // Injects the default FirebaseApp
111 allFirebaseApps: FirebaseApps, // Injects an array of all initialized Firebase Apps
112 storage: Storage, // Injects the default storage instance
113 allStorageInstances: StorageInstances, // Injects an array of all the intialized storage instances
114 ) { }
115}
116```
117How the main injection tokens (i.e, `FirebaseApp`, `Storage`) function have changed from v7 but it should provide a much more powerful and intuitive API.
118
119### API
120
121Beyond Depdency Injection AngularFire is sporting an entirely new API:
122
1231) We no longer handle lazy-loading the Firebase JS SDK modules for you
1241) We no longer provide classes beyond Depedency Injection
1251) No more Proxy / Promise-Proxy
1261) We reexport and Zone-wrap all Firebase and RxFire APIs
127
128So 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.
129
130#### Alternatives to v6 APIs
131
132<table>
133 <thead>
134 <tr>
135 <th colspan="2">v6 / Compat</th>
136 <th>v7 Modular</th>
137 </tr>
138 </thead>
139 <tbody>
140 <tr>
141 <th rowspan="3">AngularFirestore</th>
142 <td>doc</td>
143 <td>
144
145```ts
146import { doc } from '@angular/fire/firestore';
147doc<T>(firestore, 'foo/bar') // DocumentReference<T>
148```
149</td>
150 </tr>
151 <tr>
152 <td>collection</td>
153 <td>
154
155```ts
156import { collection } from '@angular/fire/firestore';
157collection<T>(firestore, 'foo') // CollectionReference<T>
158```
159</td>
160 </tr>
161 <tr>
162 <td>collectionGroup</td>
163 <td>
164
165```ts
166import { collectionGroup } from '@angular/fire/firestore';
167collectionGroup<T>(firestore, 'foo') // Query<T>
168```
169</td>
170 </tr>
171 <tr>
172 <th rowspan="7">AngularFirestoreDocument</th>
173 <td>set</td>
174 <td>
175
176```ts
177import { setDoc } from '@angular/fire/firestore';
178setDoc(docRef, { ... }) // Promise<void>
179```
180</td>
181
182</td>
183 </tr>
184 <tr>
185 <td>update</td>
186 <td>
187
188```ts
189import { updateDoc } from '@angular/fire/firestore';
190updateDoc(docRef, { ... }) // Promise<void>
191```
192</td>
193 </tr>
194 <tr>
195 <td>delete</td>
196 <td>
197
198```ts
199import { deleteDoc } from '@angular/fire/firestore';
200deleteDoc(docRef) // Promise<void>
201```
202</td>
203 </tr>
204 <tr>
205 <td>collection</td>
206 <td>
207
208```ts
209import { collection } from '@angular/fire/firestore';
210collection<T>(docRef, 'bar') // CollectionReference<T>
211```
212</td>
213 </tr>
214 <tr>
215 <td>snapshotChanges</td>
216 <td>
217
218```ts
219import { docSnapshots } from '@angular/fire/firestore';
220docSnapshots<T>(docRef) // Observable<DocumentSnapshot<T>>
221```
222</td>
223
224</td>
225 </tr>
226 <tr>
227 <td>valueChanges</td>
228 <td>
229
230```ts
231import { docData } from '@angular/fire/firestore';
232docData<T>(docRef) // Observable<T>
233```
234</td>
235 </tr>
236 <tr>
237 <td>get</td>
238 <td>
239
240```ts
241import { getDoc } from '@angular/fire/firestore';
242getDoc<T>(docRef) // Promise<DocumentSnapshot<T>>
243```
244
245</td>
246 </tr>
247 </tbody>
248</table>
249
250### Code splitting and lazy-loading
251
252AngularFire 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
253
254```ts
255// firestore_operations.ts
256import {
257 collectionData,
258 firestoreInstance$,
259 collection,
260 getFirestore
261} from '@angular/fire/firestore';
262import { first } from 'rxjs/operators';
263import { IFoo } from '../interfaces';
264
265export { getFirestore };
266
267export const fooData = firestoreInstance$.pipe(
268 first(),
269 concatMap(firestore => collectionData<IFoo>(collection(firestore, 'foo'))),
270);
271```
272
273```ts
274export class AuthService {
275 constructor() {
276 getRedirectResult().then(result => {
277 // Initialize Firestore only after a user logs in
278 if (result.user) {
279 const { getFirestore } = await import('./firestore_operations');
280 getFirestore();
281 }
282 });
283 }
284}
285```
286
287```ts
288@Component({})
289export class Foo {
290 data: Observable<IFoo[]>;
291 constructor() {
292 this.data = of(undefined).pipe(
293 concatMap(() => import('./firestore_operations')),
294 concatMap(it => it.fooData)
295 );
296 }
297}
298```