Skip to content

Commit

Permalink
Component Framework (#2378)
Browse files Browse the repository at this point in the history
* Component framework implementation (#2316)

* Component implementation

* update dep version

* [AUTOMATED]: Prettier Code Styling

* [AUTOMATED]: License Headers

* rename variables

* address comments

* [AUTOMATED]: Prettier Code Styling

* remove unused comment

* update code

* [AUTOMATED]: Prettier Code Styling

* rename to clearInstance to have naming consistency

* make FirebaseApp tests work again

* fix node tests

* [AUTOMATED]: Prettier Code Styling

* add comments for ComponentType

* [AUTOMATED]: Prettier Code Styling

* pass Component directly into Providers

* [AUTOMATED]: Prettier Code Styling

* correct spellings

* update readme

* fix lint issue

* remove unused import

* fix API change

* move types around

* [AUTOMATED]: Prettier Code Styling

* improve provider typing

* [AUTOMATED]: Prettier Code Styling

* Migrate analytics to component platform (#220)

* migrate analytics

* minor analytics refactoring

* interface merge

* [AUTOMATED]: Prettier Code Styling

* [AUTOMATED]: License Headers

* allow overwriting a registered component

* [AUTOMATED]: Prettier Code Styling

* change ComponentType to string enum

* address comments

* [AUTOMATED]: Prettier Code Styling

* remove return only generics

* Move identifier to options object for getImmediate()

* [AUTOMATED]: Prettier Code Styling

* Make getProvider() type safe

* [AUTOMATED]: Prettier Code Styling

* define a new method to replace overwrite flag

* [AUTOMATED]: Prettier Code Styling

* Make component type safe

* [AUTOMATED]: Prettier Code Styling

* remove the generic type from component container

* Update FirebaseApp and Analytics

* [AUTOMATED]: Prettier Code Styling

* remove unneccessary casting

* [AUTOMATED]: Prettier Code Styling

* fix typo

* address comments

* [AUTOMATED]: Prettier Code Styling

* update some types

* [AUTOMATED]: Prettier Code Styling

* handle errors from instance factory

* [AUTOMATED]: Prettier Code Styling

* Migrate Performance to component framework (#2325)

* Migrate Performance to component framework

* [AUTOMATED]: Prettier Code Styling

* removed unused import

* Migrate RC to component framework (#2324)

* Migrate RC to component framework

* [AUTOMATED]: Prettier Code Styling

* remove unused import

* Migrate storage to component framework (#2326)

* Migrate Database to component framework (#2327)

* Migrate Database to component framework

* revert auth formatting

* Mirgrate functions to component framework (#2328)

* Migrate installations to component framework (#2322)

* Migrate installations to component framework

* remove unused import

* update calling code according to the latest component changes

* added forceRefresh back

* Migrate messaging to component framework (#2323)

* Migrate messaging to component framework

* remove unused import

* bundle firebase services in a single object

* [AUTOMATED]: Prettier Code Styling

* [AUTOMATED]: License Headers

* address comment

* Make tests work again

* Migrate firestore to component framework (#2329)

* Migrate Firestore to component framework

* [AUTOMATED]: Prettier Code Styling

* remove unused import

* removed unnecessary type assertion

* update getImmeidate call

* Migrate testing to component framework

* [AUTOMATED]: Prettier Code Styling

* Update SDKs to use the new type system (#2358)

* update database types

* update Firestore types

* update installations type

* update messaging types

* update functions types

* update performance types

* update remoteconfig types

* update storage types

* fix analytics issue

* [AUTOMATED]: Prettier Code Styling

* [AUTOMATED]: Prettier Code Styling

* Use the new method

* Migrate Auth to component framework (#2342)

* Mirgrate Auth to component framework

* update Auth types

* [AUTOMATED]: Prettier Code Styling

* address comments

* update deps

* [AUTOMATED]: Prettier Code Styling

* Get installations service from the container (#2376)

* Get installations from the container

* [AUTOMATED]: Prettier Code Styling

* revert dev changes

* convert eslint from json to js.

* [AUTOMATED]: Prettier Code Styling

* fix broken scripts

* address comments

* [AUTOMATED]: Prettier Code Styling

* fix typos
  • Loading branch information
Feiyang1 committed Nov 26, 2019
1 parent ba2ff35 commit ae31905
Show file tree
Hide file tree
Showing 135 changed files with 3,278 additions and 1,552 deletions.
3 changes: 2 additions & 1 deletion integration/browserify/src/namespace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ firebase.initializeApp({
databaseURL: 'https://test-project-name.firebaseio.com',
projectId: 'test-project-name',
storageBucket: 'test-project-name.appspot.com',
messagingSenderId: '012345678910'
messagingSenderId: '012345678910',
appId: 'myAppId'
});

describe('Firebase Namespace Validation', function() {
Expand Down
18 changes: 3 additions & 15 deletions integration/shared/namespaceDefinition.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
},
"INTERNAL": {
"__type": "object",
"registerService": {
"registerComponent": {
"__type": "function"
},
"extendNamespace": {
Expand All @@ -55,20 +55,8 @@
"removeApp": {
"__type": "function"
},
"factories": {
"__type": "object",
"storage": {
"__type": "function"
},
"auth": {
"__type": "function"
},
"database": {
"__type": "function"
},
"messaging": {
"__type": "function"
}
"components": {
"__type": "Map"
},
"ErrorFactory": {
"__type": "function"
Expand Down
3 changes: 2 additions & 1 deletion integration/typescript/test/namespace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ firebase.initializeApp({
databaseURL: 'https://test-project-name.firebaseio.com',
projectId: 'test-project-name',
storageBucket: 'test-project-name.appspot.com',
messagingSenderId: '012345678910'
messagingSenderId: '012345678910',
appId: 'myAppId'
});

describe('Firebase Namespace Validation', function() {
Expand Down
3 changes: 2 additions & 1 deletion integration/webpack/src/namespace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ firebase.initializeApp({
databaseURL: 'https://test-project-name.firebaseio.com',
projectId: 'test-project-name',
storageBucket: 'test-project-name.appspot.com',
messagingSenderId: '012345678910'
messagingSenderId: '012345678910',
appId: 'myAppId'
});

describe('Firebase Namespace Validation', function() {
Expand Down
3 changes: 3 additions & 0 deletions packages/analytics-interop-types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @firebase/analytics-interop-types

**This package is not intended for direct usage, and should only be used via the officially supported [firebase](https://www.npmjs.com/package/firebase) package.**
48 changes: 48 additions & 0 deletions packages/analytics-interop-types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @license
* Copyright 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export interface FirebaseAnalyticsInternal {
/**
* Sends analytics event with given `eventParams`. This method
* automatically associates this logged event with this Firebase web
* app instance on this device.
* List of official event parameters can be found in
* {@link https://developers.google.com/gtagjs/reference/event
* the gtag.js reference documentation}.
*/
logEvent(
eventName: string,
eventParams?: { [key: string]: unknown },
options?: AnalyticsCallOptions
): void;
}

export interface AnalyticsCallOptions {
/**
* If true, this config or event call applies globally to all
* analytics properties on the page.
*/
global: boolean;
}

export type FirebaseAnalyticsInternalName = 'analytics-internal';

declare module '@firebase/component' {
interface NameServiceMapping {
'analytics-internal': FirebaseAnalyticsInternal;
}
}
24 changes: 24 additions & 0 deletions packages/analytics-interop-types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@firebase/analytics-interop-types",
"version": "0.1.0",
"description": "@firebase/analytics Types",
"author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)",
"license": "Apache-2.0",
"scripts": {
"test": "tsc"
},
"files": [
"index.d.ts"
],
"repository": {
"directory": "packages/analytics-interop-types",
"type": "git",
"url": "https://github.com/firebase/firebase-js-sdk.git"
},
"bugs": {
"url": "https://github.com/firebase/firebase-js-sdk/issues"
},
"devDependencies": {
"typescript": "3.7.2"
}
}
9 changes: 9 additions & 0 deletions packages/analytics-interop-types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../config/tsconfig.base.json",
"compilerOptions": {
"noEmit": true
},
"exclude": [
"dist/**/*"
]
}
6 changes: 6 additions & 0 deletions packages/analytics-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,9 @@ export interface Promotion {
id?: string;
name?: string;
}

declare module '@firebase/component' {
interface NameServiceMapping {
'analytics': FirebaseAnalytics;
}
}
25 changes: 19 additions & 6 deletions packages/analytics/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import {
factory as analyticsFactory,
resetGlobalVars
} from './index';
import { getFakeApp } from './testing/get-fake-app';
import {
getFakeApp,
getFakeInstallations
} from './testing/get-fake-firebase-services';
import { FirebaseApp } from '@firebase/app-types';
import { GtagCommand, EventName } from './src/constants';
import { findGtagScriptOnPage } from './src/helpers';
Expand All @@ -39,21 +42,29 @@ const customDataLayerName = 'customDataLayer';
describe('FirebaseAnalytics instance tests', () => {
it('Throws if no analyticsId in config', () => {
const app = getFakeApp();
expect(() => analyticsFactory(app, () => {})).to.throw('field is empty');
const installations = getFakeInstallations();
expect(() => analyticsFactory(app, installations)).to.throw(
'field is empty'
);
});
it('Throws if creating an instance with already-used analytics ID', () => {
const app = getFakeApp(analyticsId);
const installations = getFakeInstallations();
resetGlobalVars(false, { [analyticsId]: Promise.resolve() });
expect(() => analyticsFactory(app, () => {})).to.throw('already exists');
expect(() => analyticsFactory(app, installations)).to.throw(
'already exists'
);
});
describe('Standard app, page already has user gtag script', () => {
let app: FirebaseApp = {} as FirebaseApp;
before(() => {
resetGlobalVars();
app = getFakeApp(analyticsId);
const installations = getFakeInstallations();

window['gtag'] = gtagStub;
window['dataLayer'] = [];
analyticsInstance = analyticsFactory(app, () => {});
analyticsInstance = analyticsFactory(app, installations);
});
after(() => {
delete window['gtag'];
Expand Down Expand Up @@ -113,13 +124,14 @@ describe('FirebaseAnalytics instance tests', () => {
before(() => {
resetGlobalVars();
const app = getFakeApp(analyticsId);
const installations = getFakeInstallations();
window[customGtagName] = gtagStub;
window[customDataLayerName] = [];
analyticsSettings({
dataLayerName: customDataLayerName,
gtagName: customGtagName
});
analyticsInstance = analyticsFactory(app, () => {});
analyticsInstance = analyticsFactory(app, installations);
});
after(() => {
delete window[customGtagName];
Expand Down Expand Up @@ -162,7 +174,8 @@ describe('FirebaseAnalytics instance tests', () => {
before(() => {
resetGlobalVars();
const app = getFakeApp(analyticsId);
analyticsInstance = analyticsFactory(app, () => {});
const installations = getFakeInstallations();
analyticsInstance = analyticsFactory(app, installations);
});
after(() => {
delete window['gtag'];
Expand Down
56 changes: 43 additions & 13 deletions packages/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@
* limitations under the License.
*/
import firebase from '@firebase/app';
import '@firebase/installations';
import { FirebaseAnalytics } from '@firebase/analytics-types';
import {
FirebaseServiceFactory,
_FirebaseNamespace
} from '@firebase/app-types/private';
import { FirebaseAnalyticsInternal } from '@firebase/analytics-interop-types';
import { _FirebaseNamespace } from '@firebase/app-types/private';
import { factory, settings, resetGlobalVars } from './src/factory';
import { EventName } from './src/constants';
import {
Component,
ComponentType,
ComponentContainer
} from '@firebase/component';
import { ERROR_FACTORY, AnalyticsError } from './src/errors';

declare global {
interface Window {
Expand All @@ -34,18 +39,43 @@ declare global {
*/
const ANALYTICS_TYPE = 'analytics';
export function registerAnalytics(instance: _FirebaseNamespace): void {
instance.INTERNAL.registerService(
ANALYTICS_TYPE,
factory as FirebaseServiceFactory,
{
instance.INTERNAL.registerComponent(
new Component(
ANALYTICS_TYPE,
container => {
// getImmediate for FirebaseApp will always succeed
const app = container.getProvider('app').getImmediate();
const installations = container
.getProvider('installations')
.getImmediate();

return factory(app, installations);
},
ComponentType.PUBLIC
).setServiceProps({
settings,
EventName
},
// We don't need to wait on any AppHooks.
undefined,
// Allow multiple analytics instances per app.
false
})
);

instance.INTERNAL.registerComponent(
new Component('analytics-internal', internalFactory, ComponentType.PRIVATE)
);

function internalFactory(
container: ComponentContainer
): FirebaseAnalyticsInternal {
try {
const analytics = container.getProvider(ANALYTICS_TYPE).getImmediate();
return {
logEvent: analytics.logEvent
};
} catch (e) {
throw ERROR_FACTORY.create(AnalyticsError.INTEROP_COMPONENT_REG_FAILED, {
reason: e
});
}
}
}

export { factory, settings, resetGlobalVars };
Expand Down
1 change: 1 addition & 0 deletions packages/analytics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@firebase/analytics-types": "0.2.3",
"@firebase/installations": "0.3.6",
"@firebase/util": "0.2.34",
"@firebase/component": "0.1.0",
"tslib": "1.10.0"
},
"license": "Apache-2.0",
Expand Down
8 changes: 6 additions & 2 deletions packages/analytics/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import { ANALYTICS_ID_FIELD } from './constants';
export const enum AnalyticsError {
NO_GA_ID = 'no-ga-id',
ALREADY_EXISTS = 'already-exists',
ALREADY_INITIALIZED = 'already-initialized'
ALREADY_INITIALIZED = 'already-initialized',
INTEROP_COMPONENT_REG_FAILED = 'interop-component-reg-failed'
}

const ERRORS: ErrorMap<AnalyticsError> = {
Expand All @@ -36,11 +37,14 @@ const ERRORS: ErrorMap<AnalyticsError> = {
[AnalyticsError.ALREADY_INITIALIZED]:
'Firebase Analytics has already been initialized.' +
'settings() must be called before initializing any Analytics instance' +
'or it will have no effect.'
'or it will have no effect.',
[AnalyticsError.INTEROP_COMPONENT_REG_FAILED]:
'Firebase Analytics Interop Component failed to instantiate'
};

interface ErrorParams {
[AnalyticsError.ALREADY_EXISTS]: { id: string };
[AnalyticsError.INTEROP_COMPONENT_REG_FAILED]: { reason: Error };
}

export const ERROR_FACTORY = new ErrorFactory<AnalyticsError, ErrorParams>(
Expand Down
Loading

0 comments on commit ae31905

Please sign in to comment.