diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..297b6195c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,29 @@ +name: Unit tests + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2-beta + with: + node-version: '12' + check-latest: true + - name: yarn cache dir + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + - uses: actions/cache@v2 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + ${{ runner.os }}- + - name: yarn test + run: | + yarn install --frozen-lockfile --prefer-offline + yarn lint + yarn build + yarn test:all diff --git a/.gitignore b/.gitignore index 6ba88e35b..777568cf0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ test/ng-build/**/yarn.lock tools/build.js coverage *.log -api-*.json \ No newline at end of file +api-*.json +src/**/base.ts \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 229664fbd..000000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: node_js -sudo: false -node_js: 10 - -addons: - chrome: stable - -matrix: - fast_finish: true - allow_failures: - - env: CANARY=true - -branches: - only: master # otherwise pull requests get built twice - -install: yarn - -script: yarn build && yarn test:all && yarn lint diff --git a/README.md b/README.md index f8aa9ddfc..e782a1125 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,20 @@ # AngularFire The official [Angular](https://angular.io/) library for [Firebase](https://firebase.google.com/). -```bash -ng add @angular/fire -``` - -## What is AngularFire? +
ng add @angular/fire
-- **Observable based** - Use the power of RxJS, Angular, and Firebase. -- **Realtime bindings** - Synchronize data in realtime. -- **Authentication** - Log users in with a variety of providers and monitor authentication state. -- **Offline Data** - Store data offline automatically with AngularFirestore. -- **Server-side Render** - Generate static HTML to boost perceived performance or create static sites. -- **ngrx friendly** - Integrate with ngrx using AngularFire's action based APIs. -- **Manage binary data** - Upload, download, and delete binary files like images, videos, and other blobs. -- **Call server code** - Directly call serverless Cloud Functions with user context automatically passed. -- **Push notifications** - Register and listen for push notifications -- **Modular** - Include only what's needed. No AngularFire package is above 4kb with most under 2kb (gzipped). +AngularFire smooths over the rough edges an Angular developer might encounter when implementing the framework-agnostic [Firebase JS SDK](https://github.com/firebase/firebase-js-sdk) & aims to provide a more natural developer expirience by conforming to Angular conventions. -## Quickstart +- **Dependency injection** - Provide and Inject Firebase services in your components +- **Zone.js wrappers** - Stable zones allow proper functionality of service workers, forms, SSR, and pre-rendering +- **Observable based** - Utilize RxJS rather than callbacks for realtime streams +- **NgRx friendly API** - Integrate with NgRx using AngularFire's action based APIs. +- **Lazy-loading** - AngularFire dynamically imports much of Firebase, reducing time to load your app +- **Deploy schematics** - Get your Angular application deployed on Firebase Hosting with a single command +- **Google Analytics** - Zero-effort Angular Router awareness in Google Analytics +- **Router Guards** - Guard your Angular routes with built-in Firebase Authentication checks -Get your first application up and running by following [our quickstart guide](docs/install-and-setup.md). - -## Example use: +## Example use ```ts import { Component } from '@angular/core'; @@ -33,29 +25,46 @@ import { Observable } from 'rxjs'; selector: 'app-root', template: ` ` }) export class MyApp { - items: Observable; + item$: Observable; constructor(firestore: AngularFirestore) { - this.items = firestore.collection('items').valueChanges(); + this.item$ = firestore.collection('items').valueChanges(); } } ``` +## Compatibility + +| Angular | Firebase | AngularFire | +| --------|----------|--------------| +| 10 | 8 | ^6.0.4 | +| 10 | 7 | ^6.0.3 | +| 9 | 8 | ^6.0.4 | +| 9 | 7 | ^6.0 | +| 8 | 7 | ^5.2.3 | +| 8 | 6 | ^5.2.0 | + +Version combinations not documented here __may__ work but are untested and you will see NPM peer warnings. + ## Resources +[Quickstart](docs/install-and-setup.md) - Get your first application up and running by following our quickstart guide. + [Contributing](CONTRIBUTING.md) [Stackblitz Template](https://stackblitz.com/edit/angular-fire-start) - Remember to set your Firebase configuration in `app/app.module.ts`. [Upgrading to v6.0? Check out our guide.](docs/version-6-upgrade.md) -**Having troubles?** Get help on the [Firebase Mailing List](https://groups.google.com/forum/#!forum/firebase-talk) (officially supported), the [Firebase Community Slack](https://firebase.community/) (look for the `#angularfire2` room), [Gitter](https://gitter.im/angular/angularfire2), or [Stack Overflow](https://stackoverflow.com/questions/tagged/angularfire2). +**Having troubles?** Get help on the official [Firebase Mailing List](https://groups.google.com/forum/#!forum/firebase-talk), the [Firebase Community Slack](https://firebase.community/) (`#angularfire2`), the [Angular Community Discord](http://discord.gg/angular) (`#firebase`), [Gitter](https://gitter.im/angular/angularfire2), or [Stack Overflow](https://stackoverflow.com/questions/tagged/angularfire2). + +> **NOTE:** AngularFire is maintained by Googlers but is not a supported Firebase product. Questions on the mailing list and issues filed here are answered on a best-effort basis by maintainers and other community members. If you are able to reproduce a problem with Firebase outside of AngularFire's implementation, please [file an issue on the Firebase JS SDK](https://github.com/firebase/firebase-js-sdk/issues) or reach out to the personalized [Firebase support channel](https://firebase.google.com/support/). ## Developer Guide diff --git a/package.json b/package.json index 166284127..bca3c1648 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,19 @@ { "name": "@angular/fire", - "version": "6.0.4", + "version": "6.0.5", "description": "The official library of Firebase and Angular.", "private": true, "scripts": { "test": "npm run test:node", - "test:watch": "npx firebase emulators:exec --project=angularfire2-test \"npx ng test --watch=true --browsers=Chrome\"", - "test:chrome": "npx firebase emulators:exec --project=angularfire2-test \"npx ng test --watch=false --browsers=Chrome\"", - "test:chrome-headless": "npx firebase emulators:exec --project=angularfire2-test \"npx ng test --watch=false --browsers=ChromeHeadless\"", - "lint": "npx ng lint", - "test:node": "npx tsc -p tsconfig.jasmine.json; cp ./dist/packages-dist/schematics/versions.json ./dist/out-tsc/jasmine/schematics && npx firebase emulators:exec --project=angularfire2-test \"node -r tsconfig-paths/register ./tools/jasmine.js\"", + "test:watch": "firebase emulators:exec --project=angularfire2-test \"ng test --watch=true --browsers=Chrome\"", + "test:chrome": "firebase emulators:exec --project=angularfire2-test \"ng test --watch=false --browsers=Chrome\"", + "test:chrome-headless": "firebase emulators:exec --project=angularfire2-test \"ng test --watch=false --browsers=ChromeHeadless\"", + "lint": "ng lint", + "test:node": "tsc -p tsconfig.jasmine.json; cp ./dist/packages-dist/schematics/versions.json ./dist/out-tsc/jasmine/schematics && firebase emulators:exec --project=angularfire2-test \"node -r tsconfig-paths/register ./tools/jasmine.js\"", "test:typings": "node ./tools/run-typings-test.js", "test:build": "bash ./test/ng-build/build.sh", "test:all": "npm run test:node && npm run test:chrome-headless && npm run test:typings && npm run test:build", - "build": "tsc tools/build.ts; node ./tools/build.js", + "build": "ttsc -p tsconfig.build.json; node ./tools/build.js", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1" }, "husky": { @@ -30,14 +30,14 @@ ], "repository": { "type": "git", - "url": "git+https://github.com/angular/angularfire2.git" + "url": "git+https://github.com/angular/angularfire.git" }, "author": "davideast", "license": "MIT", "bugs": { - "url": "https://github.com/angular/angularfire2/issues" + "url": "https://github.com/angular/angularfire/issues" }, - "homepage": "https://github.com/angular/angularfire2#readme", + "homepage": "https://github.com/angular/angularfire#readme", "dependencies": { "@angular-devkit/architect": ">= 0.900 < 0.1100", "@angular-devkit/core": "^9.0.0 || ^10.0.0", @@ -110,9 +110,11 @@ "systemjs": "^0.19.16", "systemjs-builder": "^0.15.7", "traceur": "0.0.96", + "ts-transformer-keys": "^0.4.2", "tsconfig-paths": "^3.8.0", "tsickle": "^0.39.1", "tslint": "~6.1.0", + "ttypescript": "^1.5.12", "typedoc": "^0.16.4", "typescript": "~3.9.7" }, diff --git a/sample/.browserslistrc b/sample/.browserslistrc index 80848532e..b489a6a31 100644 --- a/sample/.browserslistrc +++ b/sample/.browserslistrc @@ -9,4 +9,5 @@ last 2 versions Firefox ESR not dead -not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file +not IE 9-10 +IE 11 \ No newline at end of file diff --git a/sample/package.json b/sample/package.json index a1ce324ea..2a76129d0 100644 --- a/sample/package.json +++ b/sample/package.json @@ -7,7 +7,9 @@ "build": "ng build", "test": "ng test", "lint": "ng lint", + "deploy": "ng deploy", "dev:ssr": "ng run sample:serve-ssr", + "bust": "rm -rf node_modules/@angular/fire && yarn cache clean @angular/fire && yarn add ../dist/packages-dist", "serve:ssr": "node dist/sample/server/main.js", "build:ssr": "ng build --prod && ng run sample:server:production", "prerender": "ng run sample:prerender" @@ -26,11 +28,13 @@ "@angular/router": "~10.2.1", "@angular/service-worker": "^10.2.1", "@nguniversal/express-engine": "~10.1.0", + "core-js": "^3.6.5", "firebase": "^8.0.0", "first-input-delay": "^0.1.3", "proxy-polyfill": "^0.3.2", "rxjs": "~6.6.3", "tslib": "^2.0.1", + "whatwg-fetch": "^3.4.1", "zone.js": "0.10.3" }, "devDependencies": { @@ -65,4 +69,4 @@ "tslint": "~6.1.3", "typescript": "~3.9.7" } -} \ No newline at end of file +} diff --git a/sample/src/app/app.module.ts b/sample/src/app/app.module.ts index d0c7bb34d..77aed53a0 100644 --- a/sample/src/app/app.module.ts +++ b/sample/src/app/app.module.ts @@ -7,7 +7,6 @@ import { ServiceWorkerModule } from '@angular/service-worker'; import { environment } from '../environments/environment'; import { AngularFireModule } from '@angular/fire'; -import { AngularFireStorageModule } from '@angular/fire/storage'; import { AngularFireAnalyticsModule, @@ -17,13 +16,13 @@ import { } from '@angular/fire/analytics'; import { FirestoreComponent } from './firestore/firestore.component'; - import { AngularFireDatabaseModule, URL as DATABASE_URL } from '@angular/fire/database'; -import { AngularFireAuthModule } from '@angular/fire/auth'; import { AngularFirestoreModule, SETTINGS as FIRESTORE_SETTINGS } 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 { AngularFireRemoteConfigModule, SETTINGS as REMOTE_CONFIG_SETTINGS } from '@angular/fire/remote-config'; +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'; import { DatabaseComponent } from './database/database.component'; @@ -53,31 +52,35 @@ const shouldUseEmulator = () => false; ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), AngularFireModule.initializeApp(environment.firebase), AngularFireStorageModule, - AngularFireAnalyticsModule, - AngularFireAuthModule, AngularFireDatabaseModule, AngularFirestoreModule.enablePersistence({ synchronizeTabs: true }), + AngularFireAuthModule, + AngularFireRemoteConfigModule, AngularFireMessagingModule, + // AngularFireAnalyticsModule, // TODO having trouble getting this to work in IE AngularFireFunctionsModule, - AngularFireRemoteConfigModule, - AngularFirePerformanceModule, + // AngularFirePerformanceModule, // TODO having trouble getting this to work in IE AngularFireAuthGuardModule ], providers: [ - UserTrackingService, - ScreenTrackingService, - PerformanceMonitoringService, - { - provide: ANALYTICS_DEBUG_MODE, - useFactory: () => isDevMode() - }, + /* + TODO Analytics and Performance monitoring aren't working in IE, sort this out + UserTrackingService, + ScreenTrackingService, + PerformanceMonitoringService, + { + provide: ANALYTICS_DEBUG_MODE, + 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: REMOTE_CONFIG_SETTINGS, useFactory: () => isDevMode() ? { minimumFetchIntervalMillis: 10_000 } : {} } + { provide: REMOTE_CONFIG_SETTINGS, useFactory: () => isDevMode() ? { minimumFetchIntervalMillis: 10_000 } : {} }, + { provide: REMOTE_CONFIG_DEFAULTS, useValue: { background_color: 'red' } }, ], bootstrap: [AppComponent] }) diff --git a/sample/src/app/database/database.component.ts b/sample/src/app/database/database.component.ts index 5367f9d4e..b2559bc5d 100644 --- a/sample/src/app/database/database.component.ts +++ b/sample/src/app/database/database.component.ts @@ -1,9 +1,10 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core'; import { AngularFireDatabase } from '@angular/fire/database'; -import { Observable } from 'rxjs'; +import { EMPTY, Observable } from 'rxjs'; import { makeStateKey, TransferState } from '@angular/platform-browser'; import { startWith, tap } from 'rxjs/operators'; import { trace } from '@angular/fire/performance'; +import { isPlatformServer } from '@angular/common'; @Component({ selector: 'app-database', @@ -19,14 +20,19 @@ export class DatabaseComponent implements OnInit { public readonly testObjectValue$: Observable; - constructor(state: TransferState, database: AngularFireDatabase) { - const doc = database.object('test'); - const key = makeStateKey(doc.query.toString()); - const existing = state.get(key, undefined); - this.testObjectValue$ = doc.valueChanges().pipe( - trace('database'), - existing ? startWith(existing) : tap(it => state.set(key, it)) - ); + constructor(state: TransferState, database: AngularFireDatabase, @Inject(PLATFORM_ID) platformId: object) { + // TODO fix the Zone.js issue with AngularFireDatabase + if (isPlatformServer(platformId)) { + this.testObjectValue$ = EMPTY; + } else { + const doc = database.object('test'); + const key = makeStateKey(doc.query.toString()); + const existing = state.get(key, undefined); + this.testObjectValue$ = doc.valueChanges().pipe( + trace('database'), + existing ? startWith(existing) : tap(it => state.set(key, it)) + ); + } } ngOnInit(): void { diff --git a/sample/src/app/home/home.component.ts b/sample/src/app/home/home.component.ts index ea36b3aee..67ec00073 100644 --- a/sample/src/app/home/home.component.ts +++ b/sample/src/app/home/home.component.ts @@ -8,10 +8,10 @@ import { FirebaseApp } from '@angular/fire'; {{ firebaseApp.name }} - - + + `, styles: [``] }) diff --git a/sample/src/app/messaging/messaging.component.ts b/sample/src/app/messaging/messaging.component.ts index c4ae51973..d3e3ca84c 100644 --- a/sample/src/app/messaging/messaging.component.ts +++ b/sample/src/app/messaging/messaging.component.ts @@ -26,6 +26,8 @@ export class MessagingComponent implements OnInit { constructor(public readonly messaging: AngularFireMessaging, readonly swpush: SwPush) { swpush.messages.subscribe(it => console.log('swpush', it)); + /* + TODO get this sorted back out with Firebase 8 messaging.usePublicVapidKey(environment.vapidKey).then(async () => { if (navigator && navigator.serviceWorker) { const registration = await navigator.serviceWorker.getRegistration(); @@ -38,7 +40,7 @@ export class MessagingComponent implements OnInit { trace('token'), tap(token => this.showRequest = !token) ); - }); + });*/ } ngOnInit(): void { diff --git a/sample/src/polyfills.ts b/sample/src/polyfills.ts index ad4c19af5..cd7bcf7c8 100644 --- a/sample/src/polyfills.ts +++ b/sample/src/polyfills.ts @@ -21,6 +21,10 @@ /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. +import 'proxy-polyfill/proxy.min.js'; +import 'core-js/stable'; +import 'whatwg-fetch'; + /** * Web Animations `@angular/platform-browser/animations` * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. @@ -61,5 +65,3 @@ import 'zone.js/dist/zone'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ - -import 'proxy-polyfill/proxy.min.js'; diff --git a/sample/yarn.lock b/sample/yarn.lock index d98f49a56..2b7354754 100644 --- a/sample/yarn.lock +++ b/sample/yarn.lock @@ -224,7 +224,7 @@ tslib "^2.0.0" "@angular/fire@../dist/packages-dist": - version "6.0.3" + version "6.0.5" dependencies: tslib "^2.0.0" @@ -3954,7 +3954,7 @@ core-js@3.6.4: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647" integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw== -core-js@3.6.5: +core-js@3.6.5, core-js@^3.6.5: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== @@ -12577,6 +12577,11 @@ whatwg-fetch@2.0.4: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== +whatwg-fetch@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" + integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ== + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" diff --git a/sample/~ngcc.config.js b/sample/~ngcc.config.js deleted file mode 100644 index 61b06c118..000000000 --- a/sample/~ngcc.config.js +++ /dev/null @@ -1,76 +0,0 @@ -module.exports = { - packages: { - "firebase": { - entryPoints: { - ".": { override: { browser: undefined } }, - "./analytics": { override: { browser: undefined } }, - "./app": {override: { browser: undefined } }, - "./auth": {override: { browser: undefined } }, - "./database": { override: { browser: undefined } }, - "./firestore": { override: { browser: undefined } }, - "./functions": { override: { browser: undefined } }, - "./installations": { override: { browser: undefined } }, - "./storage": { override: { browser: undefined } }, - "./performance": { override: { browser: undefined } }, - "./remote-config": { override: { browser: undefined } }, - }, - generateDeepReexports: true - }, - "@firebase/analytics": { - entryPoints: { ".": { override : { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/app": { - entryPoints: { ".": { override : { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/auth": { - entryPoints: { ".": { override : { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/component": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/database": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/firestore": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/functions": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/installations": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/messaging": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/storage": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/performance": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/polyfills": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/remote-config": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - "@firebase/util": { - entryPoints: { ".": { override: { browser: undefined } } }, - ignorableDeepImportMatchers: [ /@firebase\/app-types\/private/ ] - }, - } -} \ No newline at end of file diff --git a/src/analytics/analytics.module.ts b/src/analytics/analytics.module.ts index 3c104d5d3..f59ae3cac 100644 --- a/src/analytics/analytics.module.ts +++ b/src/analytics/analytics.module.ts @@ -13,6 +13,6 @@ export class AngularFireAnalyticsModule { ) { // calling anything on analytics will eagerly load the SDK // tslint:disable-next-line:no-unused-expression - analytics.app; + analytics.app.then(() => {}); } } diff --git a/src/analytics/analytics.ts b/src/analytics/analytics.ts index ce205cd91..eb8764ef7 100644 --- a/src/analytics/analytics.ts +++ b/src/analytics/analytics.ts @@ -10,9 +10,11 @@ import { FIREBASE_OPTIONS, FIREBASE_APP_NAME, ɵfirebaseAppFactory, - ɵPromiseProxy + ɵPromiseProxy, + ɵapplyMixins } from '@angular/fire'; import firebase from 'firebase/app'; +import { proxyPolyfillCompat } from './base'; export interface Config { [key: string]: any; @@ -127,3 +129,5 @@ export class AngularFireAnalytics { } } + +ɵapplyMixins(AngularFireAnalytics, [proxyPolyfillCompat]); diff --git a/src/auth/auth.ts b/src/auth/auth.ts index aa90c54de..9f148e35f 100644 --- a/src/auth/auth.ts +++ b/src/auth/auth.ts @@ -10,10 +10,12 @@ import { ɵlazySDKProxy, ɵfirebaseAppFactory, ɵAngularFireSchedulers, - ɵkeepUnstableUntilFirstFactory + ɵkeepUnstableUntilFirstFactory, + ɵapplyMixins } from '@angular/fire'; import firebase from 'firebase/app'; import { isPlatformServer } from '@angular/common'; +import { proxyPolyfillCompat } from './base'; export interface AngularFireAuth extends ɵPromiseProxy {} @@ -102,3 +104,5 @@ export class AngularFireAuth { } } + +ɵapplyMixins(AngularFireAuth, [proxyPolyfillCompat]); diff --git a/src/core/angularfire2.ts b/src/core/angularfire2.ts index 34841d582..45e452e9e 100644 --- a/src/core/angularfire2.ts +++ b/src/core/angularfire2.ts @@ -140,7 +140,7 @@ export const ɵlazySDKProxy = (klass: any, observable: Observable, zone: Ng if (klass[name]) { return klass[name]; } - if (noopFunctions.includes(name)) { + if (noopFunctions.indexOf(name) > -1) { return () => { }; } @@ -156,7 +156,7 @@ export const ɵlazySDKProxy = (klass: any, observable: Observable, zone: Ng } }); // recurse the proxy - return new Proxy(() => undefined, { + return new Proxy(() => {}, { get: (_, name) => promise[name], // TODO handle callbacks as transparently as I can apply: (self, _, args) => promise.then(it => it && it(...args)) @@ -165,3 +165,15 @@ export const ɵlazySDKProxy = (klass: any, observable: Observable, zone: Ng }) }); }; + +export const ɵapplyMixins = (derivedCtor: any, constructors: any[]) => { + constructors.forEach((baseCtor) => { + Object.getOwnPropertyNames(baseCtor.prototype || baseCtor).forEach((name) => { + Object.defineProperty( + derivedCtor.prototype, + name, + Object.getOwnPropertyDescriptor(baseCtor.prototype || baseCtor, name) + ); + }); + }); +}; diff --git a/src/functions/functions.ts b/src/functions/functions.ts index d77ed9a44..f9243172c 100644 --- a/src/functions/functions.ts +++ b/src/functions/functions.ts @@ -9,9 +9,11 @@ import { ɵAngularFireSchedulers, ɵfirebaseAppFactory, ɵlazySDKProxy, - ɵPromiseProxy + ɵPromiseProxy, + ɵapplyMixins } from '@angular/fire'; import firebase from 'firebase/app'; +import { proxyPolyfillCompat } from './base'; export const ORIGIN = new InjectionToken('angularfire2.functions.origin'); export const REGION = new InjectionToken('angularfire2.functions.region'); @@ -61,3 +63,5 @@ export class AngularFireFunctions { } } + +ɵapplyMixins(AngularFireFunctions, [proxyPolyfillCompat]); diff --git a/src/messaging/messaging.ts b/src/messaging/messaging.ts index 6fdc3b371..fe2209bee 100644 --- a/src/messaging/messaging.ts +++ b/src/messaging/messaging.ts @@ -10,9 +10,11 @@ import { ɵAngularFireSchedulers, ɵfirebaseAppFactory, ɵlazySDKProxy, - ɵPromiseProxy + ɵPromiseProxy, + ɵapplyMixins } from '@angular/fire'; import { isPlatformServer } from '@angular/common'; +import { proxyPolyfillCompat } from './base'; export interface AngularFireMessaging extends Omit<ɵPromiseProxy, 'deleteToken' | 'getToken' | 'requestPermission'> { } @@ -102,3 +104,5 @@ export class AngularFireMessaging { } } + +ɵapplyMixins(AngularFireMessaging, [proxyPolyfillCompat]); diff --git a/src/performance/performance.module.ts b/src/performance/performance.module.ts index da1ac7d78..56236076e 100644 --- a/src/performance/performance.module.ts +++ b/src/performance/performance.module.ts @@ -12,6 +12,6 @@ export class AngularFirePerformanceModule { ) { // call anything here to get perf loading // tslint:disable-next-line:no-unused-expression - perf.dataCollectionEnabled; + perf.dataCollectionEnabled.then(() => {}); } } diff --git a/src/performance/performance.service.ts b/src/performance/performance.service.ts index 4f1c6bc2f..94c532884 100644 --- a/src/performance/performance.service.ts +++ b/src/performance/performance.service.ts @@ -16,9 +16,7 @@ function markStarts() { const started = markStarts(); -@Injectable({ - providedIn: 'any' -}) +@Injectable() export class PerformanceMonitoringService implements OnDestroy { private disposable: Subscription|undefined; diff --git a/src/performance/performance.ts b/src/performance/performance.ts index 7124f91c6..965867a75 100644 --- a/src/performance/performance.ts +++ b/src/performance/performance.ts @@ -2,8 +2,9 @@ import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } fro import { EMPTY, Observable, of, Subscription } from 'rxjs'; import { map, shareReplay, switchMap, tap } from 'rxjs/operators'; import firebase from 'firebase/app'; -import { FirebaseApp, ɵlazySDKProxy, ɵPromiseProxy } from '@angular/fire'; +import { FirebaseApp, ɵapplyMixins, ɵlazySDKProxy, ɵPromiseProxy } from '@angular/fire'; import { isPlatformBrowser } from '@angular/common'; +import { proxyPolyfillCompat } from './base'; // SEMVER @ v6, drop and move core ng metrics to a service export const AUTOMATICALLY_TRACE_CORE_NG_METRICS = new InjectionToken('angularfire2.performance.auto_trace'); @@ -148,3 +149,5 @@ export const trace = (name: string) => (source$: Observable) => new ) ).subscribe(subscriber); }); + +ɵapplyMixins(AngularFirePerformance, [proxyPolyfillCompat]); diff --git a/src/remote-config/remote-config.ts b/src/remote-config/remote-config.ts index 7f1155cfc..bc0cea926 100644 --- a/src/remote-config/remote-config.ts +++ b/src/remote-config/remote-config.ts @@ -24,11 +24,13 @@ import { ɵfirebaseAppFactory, ɵkeepUnstableUntilFirstFactory, ɵlazySDKProxy, - ɵPromiseProxy + ɵPromiseProxy, + ɵapplyMixins } from '@angular/fire'; import { isPlatformBrowser } from '@angular/common'; import firebase from 'firebase/app'; import { Settings } from './interfaces'; +import { proxyPolyfillCompat } from './base'; export interface ConfigTemplate { [key: string]: string | number | boolean; @@ -310,3 +312,4 @@ export function mapToObject(to: 'numbers' | 'booleans' ); } +ɵapplyMixins(AngularFireRemoteConfig, [proxyPolyfillCompat]); diff --git a/src/schematics/deploy/functions-templates.ts b/src/schematics/deploy/functions-templates.ts index 6afe45cd8..ad67a3b8e 100644 --- a/src/schematics/deploy/functions-templates.ts +++ b/src/schematics/deploy/functions-templates.ts @@ -34,6 +34,9 @@ export const defaultFunction = ( path: string ) => `const functions = require('firebase-functions'); +// Increase readability in Cloud Logging +require("firebase-functions/lib/logger/compat"); + const expressApp = require('./${path}/main').app(); exports.${FUNCTION_NAME} = functions diff --git a/tools/build.ts b/tools/build.ts index ae2883156..93149fc5e 100644 --- a/tools/build.ts +++ b/tools/build.ts @@ -3,6 +3,8 @@ import { copy, readFile, writeFile } from 'fs-extra'; import { prettySize } from 'pretty-size'; import { sync as gzipSync } from 'gzip-size'; import { dirname, join } from 'path'; +import { keys as tsKeys } from 'ts-transformer-keys'; +import firebase from 'firebase/app'; // TODO infer these from the package.json const MODULES = [ @@ -10,9 +12,27 @@ const MODULES = [ 'firestore', 'functions', 'remote-config', 'storage', 'messaging', 'performance' ]; +const LAZY_MODULES = ['analytics', 'auth', 'functions', 'messaging', 'remote-config']; const UMD_NAMES = MODULES.map(m => m === 'core' ? 'angular-fire' : `angular-fire-${m}`); const ENTRY_NAMES = MODULES.map(m => m === 'core' ? '@angular/fire' : `@angular/fire/${m}`); +function proxyPolyfillCompat() { + const defaultObject = { + analytics: tsKeys(), + auth: tsKeys(), + functions: tsKeys(), + messaging: tsKeys(), + performance: tsKeys(), + 'remote-config': tsKeys(), + }; + + return Promise.all(Object.keys(defaultObject).map(module => + writeFile(`./src/${module}/base.ts`, `export const proxyPolyfillCompat = { +${defaultObject[module].map(it => ` ${it}: null,`).join('\n')} +};\n`) + )); +} + const src = (...args: string[]) => join(process.cwd(), 'src', ...args); const dest = (...args: string[]) => join(process.cwd(), 'dist', 'packages-dist', ...args); @@ -75,6 +95,7 @@ async function measure(module: string) { } async function buildLibrary() { + await proxyPolyfillCompat(); await spawnPromise('npx', ['ng', 'build']); await Promise.all([ copy(join(process.cwd(), '.npmignore'), dest('.npmignore')), diff --git a/tools/run-typings-test.js b/tools/run-typings-test.js index a9f43b035..059f394a3 100644 --- a/tools/run-typings-test.js +++ b/tools/run-typings-test.js @@ -35,7 +35,7 @@ ncp(pathToTestSrcFolder, pathToTestFolder, () => { .replace('{{TYPESCRIPT_VERSION}}', rootPackage.devDependencies.typescript) .replace(/\{\{ANGULAR_VERSION\}\}/g, rootPackage.dependencies['@angular/core'])); - spawnIt('yarn', ['install']) + spawnIt('yarn', ['install', '--prefer-offline']) .then(_ => spawnIt(`${pathToTestFolder}/node_modules/.bin/tsc`, ['--version'])) .then(_ => new Promise((res, rej) => { child_process.exec(`${pathToTestFolder}/node_modules/.bin/tsc --diagnostics -p ${pathToTestFolder}/tsconfig-test.json`, (err, stdout, stderr) => { diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 000000000..dd7b7cac7 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "files": [ + "tools/build.ts" + ], + "compilerOptions": { + "outDir": "tools", + "plugins": [ + { "transform": "ts-transformer-keys/transformer" } + ], + "baseUrl": "./" + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 70476b574..6a72dc364 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11438,7 +11438,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.8.1: +resolve@>=1.9.0, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.8.1: version "1.18.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== @@ -13095,6 +13095,11 @@ ts-pnp@^1.1.6: resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== +ts-transformer-keys@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/ts-transformer-keys/-/ts-transformer-keys-0.4.2.tgz#130d5b116b14d537d26aff2894dca10ac1877b22" + integrity sha512-8WVoathKnPIeZbhKuqkBKdWLq1JuiZjT5EmaKobeMI5AHQZIVLI8vyU+1h7e1YiIEIvtBUbmZ12uj2cFbgj5qg== + tsconfig-paths@^3.8.0: version "3.9.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" @@ -13156,6 +13161,13 @@ tty-browserify@0.0.0: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +ttypescript@^1.5.12: + version "1.5.12" + resolved "https://registry.yarnpkg.com/ttypescript/-/ttypescript-1.5.12.tgz#27a8356d7d4e719d0075a8feb4df14b52384f044" + integrity sha512-1ojRyJvpnmgN9kIHmUnQPlEV1gq+VVsxVYjk/NfvMlHSmYxjK5hEvOOU2MQASrbekTUiUM7pR/nXeCc8bzvMOQ== + dependencies: + resolve ">=1.9.0" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"