From 91d533b849fd74c50ae18d27f13418edbeea65f7 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 19 Nov 2020 14:03:00 -0500 Subject: [PATCH 1/4] fix(core): add requires to the UMDs and drop dyanmic imports --- sample/angular.json | 13 ------------- sample/firebase.json | 10 +++++++++- src/auth/public_api.ts | 3 +++ src/functions/functions.ts | 5 ++++- src/functions/public_api.ts | 3 +++ tools/build.ts | 25 ++++++++++++++++++++++++- 6 files changed, 43 insertions(+), 16 deletions(-) diff --git a/sample/angular.json b/sample/angular.json index 81178df28..83d8b0930 100644 --- a/sample/angular.json +++ b/sample/angular.json @@ -130,33 +130,20 @@ "tsConfig": "tsconfig.server.json", "bundleDependencies": true, "externalDependencies": [ - "firebase", "@firebase/analytics", - "@firebase/analytics-types", "@firebase/app", - "@firebase/app-types", "@firebase/auth", - "@firebase/auth-interop-types", - "@firebase/auth-types", "@firebase/component", "@firebase/database", - "@firebase/database-types", "@firebase/firestore", - "@firebase/firestore-types", "@firebase/functions", - "@firebase/functions-types", "@firebase/installations", - "@firebase/installations-types", "@firebase/logger", "@firebase/messaging", - "@firebase/messaging-types", "@firebase/performance", - "@firebase/performance-types", "@firebase/polyfill", "@firebase/remote-config", - "@firebase/remote-config-types", "@firebase/storage", - "@firebase/storage-types", "@firebase/util", "@firebase/webchannel-wrapper" ] diff --git a/sample/firebase.json b/sample/firebase.json index 0ab55f5ae..65ed0707c 100644 --- a/sample/firebase.json +++ b/sample/firebase.json @@ -15,6 +15,14 @@ "value": "public,max-age=31536000,immutable" } ] + }, { + "source": "*-sw.js", + "headers": [ + { + "key": "Cache-Control", + "value": "no-cache" + } + ] } ], "rewrites": [ @@ -26,7 +34,7 @@ } ], "functions": { - "source": "functions" + "source": "dist/sample" }, "emulators": { "functions": { diff --git a/src/auth/public_api.ts b/src/auth/public_api.ts index f570236a4..bc441937a 100644 --- a/src/auth/public_api.ts +++ b/src/auth/public_api.ts @@ -1,2 +1,5 @@ + +import 'firebase/auth'; // removed in build process when not UMD + export * from './auth'; export * from './auth.module'; diff --git a/src/functions/functions.ts b/src/functions/functions.ts index a6083f4b4..bb44a6878 100644 --- a/src/functions/functions.ts +++ b/src/functions/functions.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, NgZone, Optional } from '@angular/core'; +import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; import { from, Observable, of } from 'rxjs'; import { map, observeOn, shareReplay, switchMap } from 'rxjs/operators'; import { @@ -16,6 +16,7 @@ import firebase from 'firebase/app'; import { proxyPolyfillCompat } from './base'; import { HttpsCallableOptions } from '@firebase/functions-types'; import { ɵfetchInstance } from '@angular/fire'; +import { isPlatformServer } from '@angular/common'; export const ORIGIN = new InjectionToken('angularfire2.functions.origin'); export const REGION = new InjectionToken('angularfire2.functions.region'); @@ -45,6 +46,8 @@ export class AngularFireFunctions { @Optional() @Inject(ORIGIN) origin: string | null, @Optional() @Inject(NEW_ORIGIN_BEHAVIOR) newOriginBehavior: boolean | null, @Optional() @Inject(USE_EMULATOR) _useEmulator: any, // can't use the tuple here + // tslint:disable-next-line:ban-types + @Inject(PLATFORM_ID) platformId: Object, ) { const schedulers = new ɵAngularFireSchedulers(zone); const useEmulator: UseEmulatorArguments | null = _useEmulator; diff --git a/src/functions/public_api.ts b/src/functions/public_api.ts index ebea7ec53..1c3bb1655 100644 --- a/src/functions/public_api.ts +++ b/src/functions/public_api.ts @@ -1,2 +1,5 @@ + +import 'firebase/functions'; // removed in build process when not UMD + export * from './functions'; export * from './functions.module'; diff --git a/tools/build.ts b/tools/build.ts index 93149fc5e..b7cf5e0d0 100644 --- a/tools/build.ts +++ b/tools/build.ts @@ -94,6 +94,28 @@ async function measure(module: string) { return { size, gzip }; } +async function fixImportForLazyModules() { + await Promise.all(LAZY_MODULES.map(async module => { + const packageJson = JSON.parse((await readFile(dest(module, 'package.json'))).toString()); + const entries = Array.from(new Set(Object.values(packageJson).filter(v => typeof v === 'string' && v.endsWith('.js')))) as string[]; + // TODO don't hardcode esm2015 here, perhaps we should scan all the entry directories + // e.g, if ng-packagr starts building other non-flattened entries we'll lose the dynamic import + entries.push(`../esm2015/${module}/public_api.js`); // the import isn't pulled into the ESM public_api + await Promise.all(entries.map(async path => { + const source = (await readFile(dest(module, path))).toString(); + let newSource: string; + if (path.endsWith('.umd.js')) { + // in the UMD for lazy modules replace the dyanamic import + newSource = source.replace(`import('firebase/${module}')`, 'rxjs.of(undefined)'); + } else { + // in everything else get rid of the global side-effect import + newSource = source.replace(new RegExp(`^import 'firebase/${module}'.+$`, 'gm'), ''); + } + await writeFile(dest(module, path), newSource); + })); + })); +} + async function buildLibrary() { await proxyPolyfillCompat(); await spawnPromise('npx', ['ng', 'build']); @@ -103,7 +125,8 @@ async function buildLibrary() { copy(join(process.cwd(), 'docs'), dest('docs')), compileSchematics(), replacePackageJsonVersions(), - replacePackageCoreVersion() + replacePackageCoreVersion(), + fixImportForLazyModules(), ]); } From d1901ba995968f6a7e1e6e8cbdfbdd6a2dcb61ae Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 19 Nov 2020 14:08:02 -0500 Subject: [PATCH 2/4] Dropping the unused platformId stuff --- src/functions/functions.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/functions/functions.ts b/src/functions/functions.ts index bb44a6878..a6083f4b4 100644 --- a/src/functions/functions.ts +++ b/src/functions/functions.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, NgZone, Optional, PLATFORM_ID } from '@angular/core'; +import { Inject, Injectable, InjectionToken, NgZone, Optional } from '@angular/core'; import { from, Observable, of } from 'rxjs'; import { map, observeOn, shareReplay, switchMap } from 'rxjs/operators'; import { @@ -16,7 +16,6 @@ import firebase from 'firebase/app'; import { proxyPolyfillCompat } from './base'; import { HttpsCallableOptions } from '@firebase/functions-types'; import { ɵfetchInstance } from '@angular/fire'; -import { isPlatformServer } from '@angular/common'; export const ORIGIN = new InjectionToken('angularfire2.functions.origin'); export const REGION = new InjectionToken('angularfire2.functions.region'); @@ -46,8 +45,6 @@ export class AngularFireFunctions { @Optional() @Inject(ORIGIN) origin: string | null, @Optional() @Inject(NEW_ORIGIN_BEHAVIOR) newOriginBehavior: boolean | null, @Optional() @Inject(USE_EMULATOR) _useEmulator: any, // can't use the tuple here - // tslint:disable-next-line:ban-types - @Inject(PLATFORM_ID) platformId: Object, ) { const schedulers = new ɵAngularFireSchedulers(zone); const useEmulator: UseEmulatorArguments | null = _useEmulator; From 4d45796f2251e6d75b57b37152c960366eadb7ff Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 19 Nov 2020 19:05:24 -0500 Subject: [PATCH 3/4] Getting the sample running without any externals --- sample/angular.json | 19 +----------------- sample/firestore-protos.ts | 8 ++++++++ sample/package.json | 1 + sample/server.ts | 3 +++ sample/src/app/app.module.ts | 2 +- sample/src/app/app.server.module.ts | 6 +++++- sample/tsconfig.server.json | 3 ++- sample/yarn.lock | 30 ++++++++++++++++++++++++++++- src/firestore/firestore.ts | 2 +- 9 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 sample/firestore-protos.ts diff --git a/sample/angular.json b/sample/angular.json index 83d8b0930..bd7dc84a9 100644 --- a/sample/angular.json +++ b/sample/angular.json @@ -129,24 +129,7 @@ "main": "server.ts", "tsConfig": "tsconfig.server.json", "bundleDependencies": true, - "externalDependencies": [ - "@firebase/analytics", - "@firebase/app", - "@firebase/auth", - "@firebase/component", - "@firebase/database", - "@firebase/firestore", - "@firebase/functions", - "@firebase/installations", - "@firebase/logger", - "@firebase/messaging", - "@firebase/performance", - "@firebase/polyfill", - "@firebase/remote-config", - "@firebase/storage", - "@firebase/util", - "@firebase/webchannel-wrapper" - ] + "externalDependencies": [ ] }, "configurations": { "production": { diff --git a/sample/firestore-protos.ts b/sample/firestore-protos.ts new file mode 100644 index 000000000..7039d5f26 --- /dev/null +++ b/sample/firestore-protos.ts @@ -0,0 +1,8 @@ +module.exports = { + path: './node_modules/@firebase/firestore/dist/src/protos', + filter: /\.proto$/, + pathTransform: (_) => { + const name = _.split('./node_modules/@firebase/firestore/dist/')[1]; + return `file-loader?name=${name}!${_}`; + } +}; diff --git a/sample/package.json b/sample/package.json index dd5383d56..bc0b2860f 100644 --- a/sample/package.json +++ b/sample/package.json @@ -50,6 +50,7 @@ "@types/jasminewd2": "~2.0.3", "codelyzer": "^6.0.0", "concurrently": "^5.3.0", + "dir-loader": "^0.3.0", "express": "^4.17.1", "express-serve-static-core": "^0.1.1", "firebase-admin": "^8.13.0", diff --git a/sample/server.ts b/sample/server.ts index c59772b10..c418d506a 100644 --- a/sample/server.ts +++ b/sample/server.ts @@ -14,6 +14,9 @@ global['XMLHttpRequest'] = require('xhr2'); global['WebSocket'] = require('ws'); /* tslint:enable:no-string-literal */ +// include the protos required to bundle firestore +import 'dir-loader!./firestore-protos'; + // The Express app is exported so that it can be used by serverless Functions. export function app() { const server = express(); diff --git a/sample/src/app/app.module.ts b/sample/src/app/app.module.ts index eb921fede..cd31d6864 100644 --- a/sample/src/app/app.module.ts +++ b/sample/src/app/app.module.ts @@ -83,7 +83,7 @@ import { UpboatsComponent } from './upboats/upboats.component'; { 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: FUNCTIONS_ORIGIN, useFactory: () => isDevMode() || typeof location === 'undefined' ? 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 }, diff --git a/sample/src/app/app.server.module.ts b/sample/src/app/app.server.module.ts index 18e097f17..dd55bd1b6 100644 --- a/sample/src/app/app.server.module.ts +++ b/sample/src/app/app.server.module.ts @@ -1,8 +1,9 @@ -import { NgModule } from '@angular/core'; +import { isDevMode, NgModule } from '@angular/core'; import { ServerModule, ServerTransferStateModule } from '@angular/platform-server'; import { AppModule } from './app.module'; import { AppComponent } from './app.component'; +import { APP_BASE_HREF } from '@angular/common'; @NgModule({ imports: [ @@ -10,6 +11,9 @@ import { AppComponent } from './app.component'; ServerModule, ServerTransferStateModule ], + providers: [ + { provide: APP_BASE_HREF, useFactory: () => isDevMode() ? '/us-central1/ssr' : '/ssr' }, + ], bootstrap: [AppComponent], }) export class AppServerModule {} diff --git a/sample/tsconfig.server.json b/sample/tsconfig.server.json index 4383fc80f..4b6cf6c42 100644 --- a/sample/tsconfig.server.json +++ b/sample/tsconfig.server.json @@ -10,7 +10,8 @@ }, "files": [ "src/main.server.ts", - "server.ts" + "server.ts", + "firestore-protos.ts" ], "angularCompilerOptions": { "entryModule": "./src/app/app.server.module#AppServerModule" diff --git a/sample/yarn.lock b/sample/yarn.lock index a91db3508..e4f5c774c 100644 --- a/sample/yarn.lock +++ b/sample/yarn.lock @@ -230,7 +230,7 @@ tslib "^2.0.0" "@angular/fire@../dist/packages-dist": - version "6.1.0" + version "6.1.1" dependencies: tslib "^2.0.0" @@ -2890,6 +2890,11 @@ big-integer@^1.6.17: resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e" integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -4728,6 +4733,14 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +dir-loader@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/dir-loader/-/dir-loader-0.3.0.tgz#715b4a129a34e8e371c533625f3d7dc8428f2abe" + integrity sha1-cVtKEpo06ONxxTNiXz19yEKPKr4= + dependencies: + loader-utils "^0.2.9" + object-assign "^4.0.1" + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -7562,6 +7575,11 @@ json3@^3.3.2: resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -7897,6 +7915,16 @@ loader-utils@2.0.0, loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +loader-utils@^0.2.9: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" diff --git a/src/firestore/firestore.ts b/src/firestore/firestore.ts index 4d7a9b974..cbf68b8cb 100644 --- a/src/firestore/firestore.ts +++ b/src/firestore/firestore.ts @@ -24,8 +24,8 @@ import { FirebaseApp } from '@angular/fire'; import { isPlatformServer } from '@angular/common'; -import 'firebase/firestore'; import firebase from 'firebase/app'; +import 'firebase/firestore'; import { USE_EMULATOR as USE_AUTH_EMULATOR } from '@angular/fire/auth'; import { ɵfetchInstance, ɵlogAuthEmulatorError } from '@angular/fire'; From 9b0216ec1eb9e40542ea480d93ccb5213ac79112 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 19 Nov 2020 21:42:01 -0500 Subject: [PATCH 4/4] Cleanup --- sample/firestore-protos.ts | 6 +++--- sample/server.ts | 4 ++-- sample/src/app/app-routing.module.ts | 11 ++++++----- sample/src/app/app.component.ts | 16 +++++++++++++--- .../protected-lazy/protected-lazy.component.html | 2 +- .../src/app/secondary/secondary.component.html | 2 +- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/sample/firestore-protos.ts b/sample/firestore-protos.ts index 7039d5f26..3ce361529 100644 --- a/sample/firestore-protos.ts +++ b/sample/firestore-protos.ts @@ -1,8 +1,8 @@ module.exports = { path: './node_modules/@firebase/firestore/dist/src/protos', filter: /\.proto$/, - pathTransform: (_) => { - const name = _.split('./node_modules/@firebase/firestore/dist/')[1]; - return `file-loader?name=${name}!${_}`; + pathTransform: (path: string) => { + const name = path.split('./node_modules/@firebase/firestore/dist/')[1]; + return `file-loader?name=${name}!${path}`; } }; diff --git a/sample/server.ts b/sample/server.ts index c418d506a..a82723a8c 100644 --- a/sample/server.ts +++ b/sample/server.ts @@ -4,7 +4,7 @@ import { ngExpressEngine } from '@nguniversal/express-engine'; import * as express from 'express'; import { join } from 'path'; -import { AppServerModule } from './src/main.server'; +import { AppServerModule, } from './src/main.server'; import { APP_BASE_HREF } from '@angular/common'; import { existsSync } from 'fs'; @@ -25,7 +25,7 @@ export function app() { // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) server.engine('html', ngExpressEngine({ - bootstrap: AppServerModule, + bootstrap: AppServerModule })); server.set('view engine', 'html'); diff --git a/sample/src/app/app-routing.module.ts b/sample/src/app/app-routing.module.ts index e3eeded12..750e62d3c 100644 --- a/sample/src/app/app-routing.module.ts +++ b/sample/src/app/app-routing.module.ts @@ -2,14 +2,15 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { ProtectedComponent } from './protected/protected.component'; -import { AngularFireAuthGuard } from '@angular/fire/auth-guard'; +import { AngularFireAuthGuard, canActivate, isNotAnonymous } from '@angular/fire/auth-guard'; import { SecondaryComponent } from './secondary/secondary.component'; const routes: Routes = [ - { path: '', component: HomeComponent, outlet: 'primary' }, - { path: '', component: SecondaryComponent, outlet: 'secondary' }, - { path: '', component: SecondaryComponent, outlet: 'tertiary' }, + { path: '', component: HomeComponent, outlet: 'primary', pathMatch: 'prefix' }, + { path: '', component: SecondaryComponent, outlet: 'secondary', pathMatch: 'prefix' }, + { path: '', component: SecondaryComponent, outlet: 'tertiary', pathMatch: 'prefix' }, { path: 'protected', component: ProtectedComponent, canActivate: [AngularFireAuthGuard] }, + { path: 'lazy', loadChildren: () => import('./protected-lazy/protected-lazy.module').then(m => m.ProtectedLazyModule) }, { path: 'protected-lazy', loadChildren: () => import('./protected-lazy/protected-lazy.module').then(m => m.ProtectedLazyModule), canActivate: [AngularFireAuthGuard] }, @@ -17,7 +18,7 @@ const routes: Routes = [ { path: 'protected', component: ProtectedComponent, canActivate: [AngularFireAuthGuard], outlet: 'tertiary' }, { path: 'protected-lazy', loadChildren: () => import('./protected-lazy/protected-lazy.module').then(m => m.ProtectedLazyModule), - canActivate: [AngularFireAuthGuard], + ...canActivate(() => isNotAnonymous), outlet: 'secondary' }, ]; diff --git a/sample/src/app/app.component.ts b/sample/src/app/app.component.ts index dbe6cbc6c..9b6ffc97c 100644 --- a/sample/src/app/app.component.ts +++ b/sample/src/app/app.component.ts @@ -4,11 +4,21 @@ import { FirebaseApp } from '@angular/fire'; @Component({ selector: 'app-root', template: ` - Home | Protected | Protected Lazy | Protected Lazy Deep | Protected Lazy Deep +

AngularFire kitchen sink

+

Primary outlet

+ - Home | Protected | Protected Lazy +

Secondary outlet

+ - Home | Protected +

Yet anther outlet

+ `, styles: [``] diff --git a/sample/src/app/protected-lazy/protected-lazy.component.html b/sample/src/app/protected-lazy/protected-lazy.component.html index 7c96e988f..2d8988b8d 100644 --- a/sample/src/app/protected-lazy/protected-lazy.component.html +++ b/sample/src/app/protected-lazy/protected-lazy.component.html @@ -1,4 +1,4 @@ -

protected-lazy works!

+

lazy works!

  • diff --git a/sample/src/app/secondary/secondary.component.html b/sample/src/app/secondary/secondary.component.html index fa9404328..9ca6b12df 100644 --- a/sample/src/app/secondary/secondary.component.html +++ b/sample/src/app/secondary/secondary.component.html @@ -1 +1 @@ -

    secondary works!

    +

    I'm another outlet!