Skip to content

Commit

Permalink
feat(core): Support useEmulators, more DI, and FCM fixes (#2652)
Browse files Browse the repository at this point in the history
* Adding `USE_EMULATOR` to auth, database, firestore, and functions
* Adding `VAPID_KEY` and `SERVICE_WORKER` DI tokens to messaging
* Adding `SETTINGS`, `TENANT_ID`, `LANGUAGE_CODE`, `USE_DEVICE_LANGUAGE`, and `PERSISTENCE` DI tokens to auth
* Adding `NEW_ORIGIN_BEHAVIOR` DI token to functions, to opt-into the new way of setting `ORIGIN`
* Adding `MAX_UPLOAD_RETRY_TIME` and `MAX_OPERATION_RETRY_TIME` DI tokens to storage
* `tokenChanges` will now listen for notification permission changes and trip token detection as expected
* `httpsCallable` function now takes in `HttpsCallableOptions`
* `deleteToken`'s token argument is now optional, reflecting Firebase v8 changes
* Firestore snapshots now include metadata by default
  • Loading branch information
jamesdaniels authored Nov 13, 2020
1 parent 6c2473a commit 8d3093f
Show file tree
Hide file tree
Showing 32 changed files with 534 additions and 132 deletions.
5 changes: 4 additions & 1 deletion sample/.firebaserc
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
]
}
}
},
"projects": {
"default": "aftest-94085"
}
}
}
11 changes: 11 additions & 0 deletions sample/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
"scripts": []
},
"configurations": {
"emulated": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.emulated.ts"
}
]
},
"production": {
"fileReplacements": [
{
Expand Down Expand Up @@ -71,6 +79,9 @@
"configurations": {
"production": {
"browserTarget": "sample:build:production"
},
"emulated": {
"browserTarget": "sample:build:emulated"
}
}
},
Expand Down
42 changes: 33 additions & 9 deletions sample/firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
"ignore": [
"**/.*"
],
"headers": [{
"source": "*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)",
"headers": [{
"key": "Cache-Control",
"value": "public,max-age=31536000,immutable"
}]
}],
"headers": [
{
"source": "*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)",
"headers": [
{
"key": "Cache-Control",
"value": "public,max-age=31536000,immutable"
}
]
}
],
"rewrites": [
{
"source": "**",
Expand All @@ -22,6 +26,26 @@
}
],
"functions": {
"source": "dist/sample"
"source": "functions"
},
"emulators": {
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"database": {
"port": 9000
},
"hosting": {
"port": 5000
},
"auth": {
"port": 9099
},
"ui": {
"enabled": true
}
}
}
}
71 changes: 71 additions & 0 deletions sample/functions/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module.exports = {
env: {
browser: true,
es6: true,
node: true,
},
extends: [
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
],
parser: "@typescript-eslint/parser",
parserOptions: {
project: "tsconfig.json",
sourceType: "module",
},
plugins: [
"@typescript-eslint",
"import",
],
rules: {
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-empty-interface": "warn",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/triple-slash-reference": "error",
"@typescript-eslint/unified-signatures": "warn",
"comma-dangle": ["error", "always-multiline"],
"constructor-super": "error",
eqeqeq: ["warn", "always"],
"import/no-deprecated": "warn",
"import/no-extraneous-dependencies": "error",
"import/no-unassigned-import": "warn",
"no-cond-assign": "error",
"no-duplicate-case": "error",
"no-duplicate-imports": "error",
"no-empty": [
"error",
{
allowEmptyCatch: true,
},
],
"no-invalid-this": "error",
"no-new-wrappers": "error",
"no-param-reassign": "error",
"no-redeclare": "error",
"no-sequences": "error",
"no-shadow": [
"error",
{
hoist: "all",
},
],
"no-throw-literal": "error",
"no-unsafe-finally": "error",
"no-unused-labels": "error",
"no-var": "warn",
"no-void": "error",
"prefer-const": "warn",
},
settings: {
jsdoc: {
tagNamePreference: {
returns: "return",
},
},
},
};
12 changes: 12 additions & 0 deletions sample/functions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Compiled JavaScript files
**/*.js
**/*.js.map

# Except the ESLint config file
!.eslintrc.js

# TypeScript v1 declaration files
typings/

# Node.js dependency directory
node_modules/
30 changes: 30 additions & 0 deletions sample/functions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "functions",
"scripts": {
"lint": "eslint \"src/**/*\"",
"build": "tsc",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "12"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^9.2.0",
"firebase-functions": "^3.11.0",
"ssr-functions": "file:../dist/sample"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^3.9.1",
"@typescript-eslint/parser": "^3.8.0",
"eslint": "^7.6.0",
"eslint-plugin-import": "^2.22.0",
"typescript": "^3.8.0",
"firebase-functions-test": "^0.2.0"
},
"private": true
}
16 changes: 16 additions & 0 deletions sample/functions/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as functions from 'firebase-functions';

// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
// export const helloWorld = functions.https.onRequest((request, response) => {
// functions.logger.info("Hello logs!", {structuredData: true});
// response.send("Hello from Firebase!");
// });

// @ts-ignore
export const ssr = require('ssr-functions').ssr;

export const yada = functions.https.onCall(() => {
return { time: new Date().getTime() };
});
15 changes: 15 additions & 0 deletions sample/functions/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017"
},
"compileOnSave": true,
"include": [
"src"
]
}
5 changes: 3 additions & 2 deletions sample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"scripts": {
"ng": "ng",
"start": "ng serve",
"started:emulated": "concurrently -n ng,firebase -c red,yellow \"ng serve -c emulated\" \"firebase emulators:start\"",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
Expand Down Expand Up @@ -47,14 +48,14 @@
"@nguniversal/builders": "^10.1.0",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^14.11.2",
"codelyzer": "^6.0.0",
"concurrently": "^5.3.0",
"express": "^4.17.1",
"express-serve-static-core": "^0.1.1",
"firebase-admin": "^8.13.0",
"firebase-functions": "^3.11.0",
"firebase-functions-test": "^0.2.2",
"firebase-tools": "^8.11.1",
"firebase-tools": "^8.16.1",
"fuzzy": "^0.1.3",
"inquirer": "^6.2.2",
"inquirer-autocomplete-prompt": "^1.0.1",
Expand Down
34 changes: 18 additions & 16 deletions sample/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import {
} from '@angular/fire/analytics';

import { FirestoreComponent } from './firestore/firestore.component';
import { AngularFireDatabaseModule, URL as DATABASE_URL } from '@angular/fire/database';
import { AngularFirestoreModule, SETTINGS as FIRESTORE_SETTINGS } from '@angular/fire/firestore';
import { AngularFireDatabaseModule, USE_EMULATOR as USE_DATABASE_EMULATOR } from '@angular/fire/database';
import { AngularFirestoreModule, USE_EMULATOR as USE_FIRESTORE_EMULATOR } from '@angular/fire/firestore';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireMessagingModule } from '@angular/fire/messaging';
import { AngularFireFunctionsModule, ORIGIN as FUNCTIONS_ORIGIN } from '@angular/fire/functions';
import { AngularFireAuthModule, USE_DEVICE_LANGUAGE, USE_EMULATOR as USE_AUTH_EMULATOR } from '@angular/fire/auth';
import { AngularFireMessagingModule, SERVICE_WORKER, VAPID_KEY } from '@angular/fire/messaging';
import { AngularFireFunctionsModule, USE_EMULATOR as USE_FUNCTIONS_EMULATOR, ORIGIN as FUNCTIONS_ORIGIN, NEW_ORIGIN_BEHAVIOR } from '@angular/fire/functions';
import { AngularFireRemoteConfigModule, SETTINGS as REMOTE_CONFIG_SETTINGS, DEFAULTS as REMOTE_CONFIG_DEFAULTS } from '@angular/fire/remote-config';
import { AngularFirePerformanceModule, PerformanceMonitoringService } from '@angular/fire/performance';
import { AngularFireAuthGuardModule } from '@angular/fire/auth-guard';
Expand All @@ -31,8 +31,7 @@ import { RemoteConfigComponent } from './remote-config/remote-config.component';
import { HomeComponent } from './home/home.component';
import { AuthComponent } from './auth/auth.component';
import { MessagingComponent } from './messaging/messaging.component';

const shouldUseEmulator = () => false;
import { FunctionsComponent } from './functions/functions.component';

@NgModule({
declarations: [
Expand All @@ -43,7 +42,8 @@ const shouldUseEmulator = () => false;
RemoteConfigComponent,
HomeComponent,
AuthComponent,
MessagingComponent
MessagingComponent,
FunctionsComponent,
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
Expand Down Expand Up @@ -73,16 +73,18 @@ const shouldUseEmulator = () => false;
useFactory: () => isDevMode()
},
*/
{
provide: DATABASE_URL,
useFactory: () => shouldUseEmulator() ? `http://localhost:9000?ns=${environment.firebase.projectId}` : undefined
},
{ provide: FIRESTORE_SETTINGS, useFactory: () => shouldUseEmulator() ? { host: 'localhost:8080', ssl: false } : {} },
{ provide: FUNCTIONS_ORIGIN, useFactory: () => shouldUseEmulator() ? 'http://localhost:9999' : undefined },
{ provide: USE_AUTH_EMULATOR, useValue: environment.useEmulators ? ['localhost', 9099] : undefined },
{ provide: USE_DATABASE_EMULATOR, useValue: environment.useEmulators ? ['localhost', 9000] : undefined },
{ provide: USE_FIRESTORE_EMULATOR, useValue: environment.useEmulators ? ['localhost', 8080] : undefined },
{ provide: USE_FUNCTIONS_EMULATOR, useValue: environment.useEmulators ? ['localhost', 5001] : undefined },
{ provide: NEW_ORIGIN_BEHAVIOR, useValue: true },
{ provide: FUNCTIONS_ORIGIN, useFactory: () => isDevMode() ? undefined : location.origin },
{ provide: REMOTE_CONFIG_SETTINGS, useFactory: () => isDevMode() ? { minimumFetchIntervalMillis: 10_000 } : {} },
{ provide: REMOTE_CONFIG_DEFAULTS, useValue: { background_color: 'red' } },
{ provide: USE_DEVICE_LANGUAGE, useValue: true },
{ provide: VAPID_KEY, useValue: environment.vapidKey },
{ provide: SERVICE_WORKER, useFactory: () => navigator?.serviceWorker?.getRegistration() ?? undefined },
],
bootstrap: [AppComponent]
})
export class AppModule {
}
export class AppModule { }
25 changes: 25 additions & 0 deletions sample/src/app/functions/functions.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';

import { FunctionsComponent } from './functions.component';

describe('FunctionsComponent', () => {
let component: FunctionsComponent;
let fixture: ComponentFixture<FunctionsComponent>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ FunctionsComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(FunctionsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
30 changes: 30 additions & 0 deletions sample/src/app/functions/functions.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Component, OnInit } from '@angular/core';
import { AngularFireFunctions } from '@angular/fire/functions';
import { EMPTY, Observable } from 'rxjs';

@Component({
selector: 'app-functions',
template: `
<p>
Functions!
{{ response$ | async | json }}
<button (click)="request()">Call!</button>
</p>
`,
styles: []
})
export class FunctionsComponent implements OnInit {

response$: Observable<any>;

constructor(public readonly functions: AngularFireFunctions) {
this.response$ = EMPTY;
}

ngOnInit(): void {}

request() {
this.response$ = this.functions.httpsCallable('yada', { timeout: 3 })({});
}

}
Loading

0 comments on commit 8d3093f

Please sign in to comment.