Skip to content

Commit 1868406

Browse files
committed
Adding compat packages
1 parent c85d200 commit 1868406

File tree

131 files changed

+6916
-394
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

131 files changed

+6916
-394
lines changed

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
{
22
"name": "@angular/fire",
3-
"version": "6.1.4",
3+
"version": "7.0.0",
44
"description": "The official Angular library for Firebase.",
55
"private": true,
66
"scripts": {
7-
"test": "npm run build:jasmine && npm run test:node",
7+
"test": "npm run build:jasmine && npm run test:node && npm run test:chrome-headless",
88
"test:watch": "firebase emulators:exec --project=angularfire2-test \"ng test --watch=true --browsers=Chrome\"",
99
"test:chrome": "firebase emulators:exec --project=angularfire2-test \"ng test --watch=false --browsers=Chrome\"",
1010
"test:chrome-headless": "firebase emulators:exec --project=angularfire2-test \"ng test --watch=false --browsers=ChromeHeadless\"",
1111
"lint": "ng lint",
12-
"test:node": "firebase emulators:exec --project=angularfire2-test \"node -r tsconfig-paths/register ./tools/jasmine.js\"",
12+
"test:node": "node -r tsconfig-paths/register ./tools/jasmine.js",
1313
"test:typings": "node ./tools/run-typings-test.js",
1414
"test:build": "bash ./test/ng-build/build.sh",
1515
"test:all": "npm run test:node && npm run test:chrome-headless && npm run test:typings && npm run test:build",
16-
"build": "ttsc -p tsconfig.build.json; node ./tools/build.js",
16+
"build": "ttsc -p tsconfig.build.json; node --trace-warnings ./tools/build.js",
1717
"build:jasmine": "tsc -p tsconfig.jasmine.json; cp ./dist/packages-dist/schematics/versions.json ./dist/out-tsc/jasmine/schematics",
1818
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1"
1919
},
@@ -49,7 +49,7 @@
4949
"@angular/platform-browser": "^9.0.0 || ^10.0.0 || ^11.0.0",
5050
"@angular/platform-browser-dynamic": "^9.0.0 || ^10.0.0 || ^11.0.0",
5151
"@angular/router": "^9.0.0 || ^10.0.0 || ^11.0.0",
52-
"firebase": "^0.900.15",
52+
"firebase": "^9.0.0-beta.1",
5353
"firebase-admin": "^8.10.0",
5454
"firebase-functions": "^3.6.0",
5555
"firebase-tools": "^8.0.0",

src/auth/auth.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ describe('AngularFireAuth', () => {
6969
});
7070

7171
it('should have an initialized Firebase app', () => {
72-
expect(afAuth.app).toBeDefined();
72+
expect(afAuth.name).toBeDefined();
7373
});
7474

7575
it('should emit auth updates through authState', (done: any) => {
@@ -152,12 +152,12 @@ describe('AngularFireAuth with different app', () => {
152152
});
153153

154154
it('should have an initialized Firebase app', () => {
155-
expect(afAuth.app).toBeDefined();
155+
expect(afAuth.name).toBeDefined();
156156
});
157157

158158
it('should have an initialized Firebase app instance member', async () => {
159-
const app = await afAuth.app;
160-
expect(app.name).toEqual(firebaseAppName);
159+
const appName = await afAuth.name;
160+
expect(appName).toEqual(firebaseAppName);
161161
});
162162
});
163163

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { NgModule, Optional } from '@angular/core';
2+
import { ScreenTrackingService } from './screen-tracking.service';
3+
import { AngularFireAnalytics } from './analytics';
4+
import { UserTrackingService } from './user-tracking.service';
5+
6+
@NgModule({
7+
providers: [ AngularFireAnalytics ]
8+
})
9+
export class AngularFireAnalyticsModule {
10+
constructor(
11+
analytics: AngularFireAnalytics,
12+
@Optional() screenTracking: ScreenTrackingService,
13+
@Optional() userTracking: UserTrackingService
14+
) {
15+
// calling anything on analytics will eagerly load the SDK
16+
// tslint:disable-next-line:no-unused-expression
17+
analytics.app.then(() => {});
18+
}
19+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { TestBed } from '@angular/core/testing';
2+
import { AngularFireModule, FirebaseApp } from '@angular/fire/compat';
3+
import { AngularFireAnalytics, AngularFireAnalyticsModule } from '@angular/fire/compat/analytics';
4+
import { COMMON_CONFIG } from '../../test-config';
5+
import { rando } from '../firestore/utils.spec';
6+
7+
8+
describe('AngularFireAnalytics', () => {
9+
let app: FirebaseApp;
10+
let analytics: AngularFireAnalytics;
11+
12+
beforeEach(() => {
13+
TestBed.configureTestingModule({
14+
imports: [
15+
AngularFireModule.initializeApp(COMMON_CONFIG, rando()),
16+
AngularFireAnalyticsModule
17+
]
18+
});
19+
20+
app = TestBed.inject(FirebaseApp);
21+
analytics = TestBed.inject(AngularFireAnalytics);
22+
});
23+
24+
afterEach(() => {
25+
app.delete();
26+
});
27+
28+
it('should be exist', () => {
29+
expect(analytics instanceof AngularFireAnalytics).toBe(true);
30+
});
31+
32+
it('should have the Firebase Functions instance', () => {
33+
expect(analytics.app).toBeDefined();
34+
});
35+
36+
});

src/compat/analytics/analytics.ts

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core';
2+
import { EMPTY, of } from 'rxjs';
3+
import { isPlatformBrowser } from '@angular/common';
4+
import { map, shareReplay, switchMap, observeOn } from 'rxjs/operators';
5+
import {
6+
ɵAngularFireSchedulers,
7+
ɵlazySDKProxy,
8+
ɵPromiseProxy,
9+
ɵapplyMixins,
10+
} from '@angular/fire';
11+
import { FirebaseApp } from '@angular/fire/compat';
12+
import firebase from 'firebase/compat/app';
13+
import { proxyPolyfillCompat } from './base';
14+
import { ɵfetchInstance } from '@angular/fire';
15+
16+
export interface Config {
17+
[key: string]: any;
18+
}
19+
20+
export const COLLECTION_ENABLED = new InjectionToken<boolean>('angularfire2.analytics.analyticsCollectionEnabled');
21+
export const APP_VERSION = new InjectionToken<string>('angularfire2.analytics.appVersion');
22+
export const APP_NAME = new InjectionToken<string>('angularfire2.analytics.appName');
23+
export const DEBUG_MODE = new InjectionToken<boolean>('angularfire2.analytics.debugMode');
24+
export const CONFIG = new InjectionToken<Config>('angularfire2.analytics.config');
25+
26+
const APP_NAME_KEY = 'app_name';
27+
const APP_VERSION_KEY = 'app_version';
28+
const DEBUG_MODE_KEY = 'debug_mode';
29+
const GTAG_CONFIG_COMMAND = 'config';
30+
const GTAG_FUNCTION_NAME = 'gtag'; // TODO rename these
31+
const DATA_LAYER_NAME = 'dataLayer';
32+
const SEND_TO_KEY = 'send_to';
33+
34+
export interface AngularFireAnalytics extends ɵPromiseProxy<firebase.analytics.Analytics> {
35+
}
36+
37+
@Injectable({
38+
providedIn: 'any'
39+
})
40+
export class AngularFireAnalytics {
41+
42+
private measurementId: string;
43+
private analyticsInitialized: Promise<void> = new Promise(() => {});
44+
45+
async updateConfig(config: Config) {
46+
await this.analyticsInitialized;
47+
window[GTAG_FUNCTION_NAME](GTAG_CONFIG_COMMAND, this.measurementId, { ...config, update: true });
48+
}
49+
50+
constructor(
51+
app: FirebaseApp,
52+
@Optional() @Inject(COLLECTION_ENABLED) analyticsCollectionEnabled: boolean | null,
53+
@Optional() @Inject(APP_VERSION) providedAppVersion: string | null,
54+
@Optional() @Inject(APP_NAME) providedAppName: string | null,
55+
@Optional() @Inject(DEBUG_MODE) debugModeEnabled: boolean | null,
56+
@Optional() @Inject(CONFIG) providedConfig: Config | null,
57+
// tslint:disable-next-line:ban-types
58+
@Inject(PLATFORM_ID) platformId: Object,
59+
zone: NgZone
60+
) {
61+
62+
if (isPlatformBrowser(platformId)) {
63+
64+
window[DATA_LAYER_NAME] = window[DATA_LAYER_NAME] || [];
65+
66+
// It turns out we can't rely on the measurementId in the Firebase config JSON
67+
// this identifier is not stable. firebase/analytics does a call to get a fresh value
68+
// falling back on the one in the config. Rather than do that ourselves we should listen
69+
// on our gtag function for a analytics config command
70+
// e.g, ['config', measurementId, { origin: 'firebase', firebase_id }]
71+
const parseMeasurementId = (...args: any[]) => {
72+
if (args[0] === 'config' && args[2].origin === 'firebase') {
73+
this.measurementId = args[1];
74+
return true;
75+
} else {
76+
return false;
77+
}
78+
};
79+
80+
const patchGtag = (fn?: (...args: any[]) => void) => {
81+
window[GTAG_FUNCTION_NAME] = (...args: any[]) => {
82+
if (fn) {
83+
fn(...args);
84+
}
85+
// Inject app_name and app_version into events
86+
// TODO(jamesdaniels): I'm doing this as documented but it's still not
87+
// showing up in the console. Investigate. Guessing it's just part of the
88+
// whole GA4 transition mess.
89+
if (args[0] === 'event' && args[2][SEND_TO_KEY] === this.measurementId) {
90+
if (providedAppName) {
91+
args[2][APP_NAME_KEY] = providedAppName;
92+
}
93+
if (providedAppVersion) {
94+
args[2][APP_VERSION_KEY] = providedAppVersion;
95+
}
96+
}
97+
if (debugModeEnabled && typeof console !== 'undefined') {
98+
// tslint:disable-next-line:no-console
99+
console.info(...args);
100+
}
101+
/**
102+
* According to the gtag documentation, this function that defines a custom data layer cannot be
103+
* an arrow function because 'arguments' is not an array. It is actually an object that behaves
104+
* like an array and contains more information then just indexes. Transforming this into arrow function
105+
* caused issue #2505 where analytics no longer sent any data.
106+
*/
107+
// tslint:disable-next-line: only-arrow-functions
108+
(function(..._args: any[]) {
109+
window[DATA_LAYER_NAME].push(arguments);
110+
})(...args);
111+
};
112+
};
113+
114+
// Unclear if we still need to but I was running into config/events I passed
115+
// to gtag before ['js' timestamp] weren't getting parsed, so let's make a promise
116+
// that resolves when firebase/analytics has configured gtag.js that we wait on
117+
// before sending anything
118+
const firebaseAnalyticsAlreadyInitialized = window[DATA_LAYER_NAME].some(parseMeasurementId);
119+
if (firebaseAnalyticsAlreadyInitialized) {
120+
this.analyticsInitialized = Promise.resolve();
121+
patchGtag();
122+
} else {
123+
this.analyticsInitialized = new Promise(resolve => {
124+
patchGtag((...args) => {
125+
if (parseMeasurementId(...args)) {
126+
resolve();
127+
}
128+
});
129+
});
130+
}
131+
132+
if (providedConfig) {
133+
this.updateConfig(providedConfig);
134+
}
135+
if (debugModeEnabled) {
136+
this.updateConfig({ [DEBUG_MODE_KEY]: 1 });
137+
}
138+
139+
} else {
140+
141+
this.analyticsInitialized = Promise.resolve();
142+
143+
}
144+
145+
const analytics = of(undefined).pipe(
146+
observeOn(new ɵAngularFireSchedulers(zone).outsideAngular),
147+
switchMap(() => isPlatformBrowser(platformId) ? zone.runOutsideAngular(() => import('firebase/compat/analytics')) : EMPTY),
148+
// SEMVER can switch to isSupported() when we only target v8
149+
// switchMap(() => firebase.analytics.isSupported().then(it => it, () => false)),
150+
// TODO server-side investigate use of the Universal Analytics API
151+
// switchMap(supported => supported ? of(undefined) : EMPTY),
152+
map(() => {
153+
return ɵfetchInstance(`analytics`, 'AngularFireAnalytics', app, () => {
154+
const analytics = app.analytics();
155+
if (analyticsCollectionEnabled === false) {
156+
analytics.setAnalyticsCollectionEnabled(false);
157+
}
158+
return analytics;
159+
}, [app, analyticsCollectionEnabled, providedConfig, debugModeEnabled]);
160+
}),
161+
shareReplay({ bufferSize: 1, refCount: false })
162+
);
163+
164+
return ɵlazySDKProxy(this, analytics, zone);
165+
166+
}
167+
168+
}
169+
170+
ɵapplyMixins(AngularFireAnalytics, [proxyPolyfillCompat]);

src/compat/analytics/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './public_api';

src/compat/analytics/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "../../../node_modules/ng-packagr/package.schema.json",
3+
"ngPackage": {
4+
"lib": {
5+
"umdModuleIds": {
6+
"firebase/compat/app": "firebase"
7+
},
8+
"entryFile": "public_api.ts"
9+
}
10+
}
11+
}

src/compat/analytics/public_api.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './analytics';
2+
export * from './analytics.module';
3+
export * from './screen-tracking.service';
4+
export * from './user-tracking.service';

0 commit comments

Comments
 (0)