Skip to content

Commit be58c6b

Browse files
jamesdanielsdavideast
authored andcommitted
fix(): Fixing Zone.js issues (#1586)
* fix(): Fixing Zone.js issues * Trying out only blocking on platformServer * yarn upgrade
1 parent f2cf159 commit be58c6b

17 files changed

+493
-1083
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angularfire2",
3-
"version": "5.0.0-rc.6",
3+
"version": "5.0.0-rc.7.2-next",
44
"description": "The official library of Firebase and Angular.",
55
"private": true,
66
"scripts": {

src/auth/auth.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { FirebaseAuth, User } from '@firebase/auth-types';
22
import { FirebaseOptions } from '@firebase/app-types';
3-
import { Injectable, Inject, Optional, NgZone } from '@angular/core';
3+
import { Injectable, Inject, Optional, NgZone, PLATFORM_ID } from '@angular/core';
44
import { Observable } from 'rxjs/Observable';
5-
import { observeOn } from 'rxjs/operator/observeOn';
65

76
import { FirebaseAppConfig, FirebaseAppName, _firebaseAppFactory, FirebaseZoneScheduler } from 'angularfire2';
87

@@ -31,9 +30,10 @@ export class AngularFireAuth {
3130
constructor(
3231
@Inject(FirebaseAppConfig) config:FirebaseOptions,
3332
@Optional() @Inject(FirebaseAppName) name:string,
33+
@Inject(PLATFORM_ID) platformId: Object,
3434
private zone: NgZone
3535
) {
36-
const scheduler = new FirebaseZoneScheduler(zone);
36+
const scheduler = new FirebaseZoneScheduler(zone, platformId);
3737
this.auth = zone.runOutsideAngular(() => {
3838
const app = _firebaseAppFactory(config, name);
3939
return app.auth();

src/core/angularfire2.ts

+20-13
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { InjectionToken, NgZone } from '@angular/core';
2-
import { Subscription } from 'rxjs/Subscription';
32
import { Observable } from 'rxjs/Observable';
3+
import { Subscription } from 'rxjs/Subscription';
44
import { queue } from 'rxjs/scheduler/queue';
5+
import { isPlatformServer } from '@angular/common';
6+
import { observeOn } from 'rxjs/operator/observeOn';
57

68
import firebase from '@firebase/app';
79
import { FirebaseApp, FirebaseOptions } from '@firebase/app-types';
810

911
import 'zone.js';
1012
import 'rxjs/add/operator/first';
11-
import { Subscriber } from 'rxjs/Subscriber';
12-
import { observeOn } from 'rxjs/operator/observeOn';
1313

1414
export const FirebaseAppName = new InjectionToken<string>('angularfire2.appName');
1515
export const FirebaseAppConfig = new InjectionToken<FirebaseOptions>('angularfire2.config');
@@ -18,25 +18,32 @@ export const FirebaseAppConfig = new InjectionToken<FirebaseOptions>('angularfir
1818
export const RealtimeDatabaseURL = new InjectionToken<string>('angularfire2.realtimeDatabaseURL');
1919

2020
export class FirebaseZoneScheduler {
21-
constructor(public zone: NgZone) {}
21+
constructor(public zone: NgZone, private platformId: Object) {}
2222
schedule(...args: any[]): Subscription {
2323
return <Subscription>this.zone.runGuarded(function() { return queue.schedule.apply(queue, args)});
2424
}
2525
// TODO this is a hack, clean it up
2626
keepUnstableUntilFirst<T>(obs$: Observable<T>) {
27-
return new Observable<T>(subscriber => {
28-
const noop = () => {};
29-
const task = Zone.current.scheduleMacroTask('firebaseZoneBlock', noop, {}, noop, noop);
30-
obs$.first().subscribe(() => this.zone.runOutsideAngular(() => task.invoke()));
31-
return obs$.subscribe(subscriber);
32-
});
27+
if (isPlatformServer(this.platformId)) {
28+
return new Observable<T>(subscriber => {
29+
const noop = () => {};
30+
const task = Zone.current.scheduleMacroTask('firebaseZoneBlock', noop, {}, noop, noop);
31+
obs$.first().subscribe(() => this.zone.runOutsideAngular(() => task.invoke()));
32+
return obs$.subscribe(subscriber);
33+
});
34+
} else {
35+
return obs$;
36+
}
3337
}
3438
runOutsideAngular<T>(obs$: Observable<T>): Observable<T> {
35-
const outsideAngular = new Observable<T>(subscriber => {
39+
return new Observable<T>(subscriber => {
3640
return this.zone.runOutsideAngular(() => {
37-
return obs$.subscribe(subscriber);
41+
return obs$.subscribe(
42+
value => this.zone.run(() => subscriber.next(value)),
43+
error => this.zone.run(() => subscriber.error(error)),
44+
() => this.zone.run(() => subscriber.complete()),
45+
);
3846
});
3947
});
40-
return observeOn.call(outsideAngular, this);
4148
}
4249
}

src/database-deprecated/firebase_list_factory.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ function firebaseListObservable(ref: database.Reference | DatabaseQuery, {preser
187187
});
188188

189189
// TODO: should be in the subscription zone instead
190-
return observeOn.call(listObs, new FirebaseZoneScheduler(new NgZone({})));
190+
return observeOn.call(listObs, new FirebaseZoneScheduler(new NgZone({}), {}));
191191

192192
}
193193

src/database-deprecated/firebase_object_factory.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ export function FirebaseObjectFactory (
2222
}, ref);
2323

2424
// TODO: should be in the subscription zone instead
25-
return observeOn.call(objectObservable, new FirebaseZoneScheduler(new NgZone({})));
25+
return observeOn.call(objectObservable, new FirebaseZoneScheduler(new NgZone({}), {}));
2626
}

src/database/database.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ describe('AngularFireDatabase', () => {
4242
});
4343

4444
it('should accept a Firebase App in the constructor', () => {
45-
const __db = new AngularFireDatabase(app.options, app.name, null!, zone);
45+
const __db = new AngularFireDatabase(app.options, app.name, null!, {}, zone);
4646
expect(__db instanceof AngularFireDatabase).toEqual(true);
4747
});
4848

src/database/database.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Injectable, Inject, Optional, NgZone } from '@angular/core';
1+
import { Injectable, Inject, Optional, NgZone, PLATFORM_ID } from '@angular/core';
22
import { FirebaseDatabase } from '@firebase/database-types';
33
import { PathReference, DatabaseQuery, DatabaseReference, DatabaseSnapshot, ChildEvent, ListenEvent, QueryFn, AngularFireList, AngularFireObject } from './interfaces';
44
import { getRef } from './utils';
@@ -17,9 +17,10 @@ export class AngularFireDatabase {
1717
@Inject(FirebaseAppConfig) config:FirebaseOptions,
1818
@Optional() @Inject(FirebaseAppName) name:string,
1919
@Optional() @Inject(RealtimeDatabaseURL) databaseURL:string,
20+
@Inject(PLATFORM_ID) platformId: Object,
2021
zone: NgZone
2122
) {
22-
this.scheduler = new FirebaseZoneScheduler(zone);
23+
this.scheduler = new FirebaseZoneScheduler(zone, platformId);
2324
this.database = zone.runOutsideAngular(() => {
2425
const app = _firebaseAppFactory(config, name);
2526
return app.database(databaseURL || undefined);

src/database/list/audit-trail.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import 'rxjs/add/operator/withLatestFrom';
1010
import 'rxjs/add/operator/map';
1111

1212
export function createAuditTrail(query: DatabaseQuery, afDatabase: AngularFireDatabase) {
13-
return (events?: ChildEvent[]) => afDatabase.scheduler.keepUnstableUntilFirst(auditTrail(query, events));
13+
return (events?: ChildEvent[]) => afDatabase.scheduler.keepUnstableUntilFirst(
14+
afDatabase.scheduler.runOutsideAngular(
15+
auditTrail(query, events)
16+
)
17+
);
1418
}
1519

1620
export function auditTrail(query: DatabaseQuery, events?: ChildEvent[]): Observable<SnapshotAction[]> {

src/database/list/create-reference.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,21 @@ export function createListReference<T>(query: DatabaseQuery, afDatabase: Angular
1515
remove: createRemoveMethod(query.ref),
1616
snapshotChanges(events?: ChildEvent[]) {
1717
const snapshotChanges$ = snapshotChanges(query, events);
18-
return afDatabase.scheduler.keepUnstableUntilFirst(snapshotChanges$);
18+
return afDatabase.scheduler.keepUnstableUntilFirst(
19+
afDatabase.scheduler.runOutsideAngular(
20+
snapshotChanges$
21+
)
22+
);
1923
},
2024
stateChanges: createStateChanges(query, afDatabase),
2125
auditTrail: createAuditTrail(query, afDatabase),
2226
valueChanges<T>(events?: ChildEvent[]) {
2327
const snapshotChanges$ = snapshotChanges(query, events);
24-
return afDatabase.scheduler.keepUnstableUntilFirst(snapshotChanges$)
25-
.map(actions => actions.map(a => a.payload.val()));
28+
return afDatabase.scheduler.keepUnstableUntilFirst(
29+
afDatabase.scheduler.runOutsideAngular(
30+
snapshotChanges$
31+
)
32+
).map(actions => actions.map(a => a.payload.val()));
2633
}
2734
}
2835
}

src/database/list/state-changes.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import { DataSnapshot } from '@firebase/database-types';
88
import { AngularFireDatabase } from '../database';
99

1010
export function createStateChanges(query: DatabaseQuery, afDatabase: AngularFireDatabase) {
11-
return (events?: ChildEvent[]) => afDatabase.scheduler.keepUnstableUntilFirst(stateChanges(query, events));
11+
return (events?: ChildEvent[]) => afDatabase.scheduler.keepUnstableUntilFirst(
12+
afDatabase.scheduler.runOutsideAngular(
13+
stateChanges(query, events)
14+
)
15+
);
1216
}
1317

1418
export function stateChanges(query: DatabaseQuery, events?: ChildEvent[]) {

src/database/object/create-reference.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,22 @@ export function createObjectReference<T>(query: DatabaseQuery, afDatabase: Angul
77
query,
88
snapshotChanges<T>() {
99
const snapshotChanges$ = createObjectSnapshotChanges(query)();
10-
return afDatabase.scheduler.keepUnstableUntilFirst(snapshotChanges$);
10+
return afDatabase.scheduler.keepUnstableUntilFirst(
11+
afDatabase.scheduler.runOutsideAngular(
12+
snapshotChanges$
13+
)
14+
);
1115
},
1216
update(data: Partial<T>) { return query.ref.update(data as any) as Promise<void>; },
1317
set(data: T) { return query.ref.set(data) as Promise<void>; },
1418
remove() { return query.ref.remove() as Promise<void>; },
1519
valueChanges<T>() {
1620
const snapshotChanges$ = createObjectSnapshotChanges(query)();
17-
return afDatabase.scheduler.keepUnstableUntilFirst(snapshotChanges$)
18-
.map(action => action.payload.exists() ? action.payload.val() as T : null)
21+
return afDatabase.scheduler.keepUnstableUntilFirst(
22+
afDatabase.scheduler.runOutsideAngular(
23+
snapshotChanges$
24+
)
25+
).map(action => action.payload.exists() ? action.payload.val() as T : null)
1926
},
2027
}
2128
}

src/database/observable/fromRef.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { DatabaseQuery, DatabaseSnapshot, ListenEvent, AngularFireAction } from '../interfaces';
22
import { Observable } from 'rxjs/Observable';
3-
import { observeOn } from 'rxjs/operator/observeOn';
43
import { FirebaseZoneScheduler } from 'angularfire2';
54
import 'rxjs/add/operator/map';
65
import 'rxjs/add/operator/delay';

src/firestore/collection/collection.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import { docChanges, sortedChanges } from './changes';
1212
import { AngularFirestoreDocument } from '../document/document';
1313
import { AngularFirestore } from '../firestore';
1414

15-
import { observeOn } from 'rxjs/operator/observeOn';
16-
1715
import 'rxjs/add/observable/of';
1816

1917
export function validateEventsArray(events?: DocumentChangeType[]) {
@@ -70,11 +68,19 @@ export class AngularFirestoreCollection<T> {
7068
*/
7169
stateChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction[]> {
7270
if(!events || events.length === 0) {
73-
return docChanges(this.query);
71+
return this.afs.scheduler.keepUnstableUntilFirst(
72+
this.afs.scheduler.runOutsideAngular(
73+
docChanges(this.query)
74+
)
75+
);
7476
}
75-
return this.afs.scheduler.keepUnstableUntilFirst(docChanges(this.query)
77+
return this.afs.scheduler.keepUnstableUntilFirst(
78+
this.afs.scheduler.runOutsideAngular(
79+
docChanges(this.query)
80+
)
81+
)
7682
.map(actions => actions.filter(change => events.indexOf(change.type) > -1))
77-
.filter(changes => changes.length > 0));
83+
.filter(changes => changes.length > 0);
7884
}
7985

8086
/**

src/firestore/firestore.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { InjectionToken, NgZone } from '@angular/core';
1+
import { InjectionToken, NgZone, PLATFORM_ID } from '@angular/core';
22
import { FirebaseFirestore, CollectionReference, DocumentReference } from '@firebase/firestore-types';
33

44
import { Observable } from 'rxjs/Observable';
@@ -112,9 +112,10 @@ export class AngularFirestore {
112112
@Inject(FirebaseAppConfig) config:FirebaseOptions,
113113
@Optional() @Inject(FirebaseAppName) name:string,
114114
@Optional() @Inject(EnablePersistenceToken) shouldEnablePersistence: boolean,
115+
@Inject(PLATFORM_ID) platformId: Object,
115116
zone: NgZone
116117
) {
117-
this.scheduler = new FirebaseZoneScheduler(zone);
118+
this.scheduler = new FirebaseZoneScheduler(zone, platformId);
118119
this.firestore = zone.runOutsideAngular(() => {
119120
const app = _firebaseAppFactory(config, name);
120121
return app.firestore();

src/storage/storage.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Injectable, Inject, Optional, InjectionToken, NgZone } from '@angular/core';
1+
import { Injectable, Inject, Optional, InjectionToken, NgZone, PLATFORM_ID } from '@angular/core';
22
import { FirebaseStorage, UploadMetadata } from '@firebase/storage-types';
33
import { createStorageRef, AngularFireStorageReference } from './ref';
44
import { createUploadTask, AngularFireUploadTask } from './task';
@@ -24,9 +24,10 @@ export class AngularFireStorage {
2424
@Inject(FirebaseAppConfig) config:FirebaseOptions,
2525
@Optional() @Inject(FirebaseAppName) name:string,
2626
@Optional() @Inject(StorageBucket) storageBucket:string,
27+
@Inject(PLATFORM_ID) platformId: Object,
2728
zone: NgZone
2829
) {
29-
this.scheduler = new FirebaseZoneScheduler(zone);
30+
this.scheduler = new FirebaseZoneScheduler(zone, platformId);
3031
this.storage = zone.runOutsideAngular(() => {
3132
const app = _firebaseAppFactory(config, name);
3233
return app.storage(storageBucket || undefined);

tools/build.js

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const GLOBALS = {
5454
'rxjs/observable/from': 'Rx.Observable',
5555
'rxjs/operator': 'Rx.Observable.prototype',
5656
'@angular/core': 'ng.core',
57+
'@angular/common': 'ng.common',
5758
'@angular/compiler': 'ng.compiler',
5859
'@angular/platform-browser': 'ng.platformBrowser',
5960
'firebase/auth': 'firebase',

0 commit comments

Comments
 (0)