Skip to content

feat(core): Support useEmulators, more DI, and FCM fixes #2652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 13, 2020
Merged
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