angular / angularfire

Angular + Firebase = ❤️
https://firebaseopensource.com/projects/angular/angularfire2
MIT License
7.69k stars 2.19k forks source link

AngularFireStore breaks SSR, does not render web page #2420

Closed tskweres closed 3 years ago

tskweres commented 4 years ago

Test Repo here, simply clone it, npm install, and npm run dev:ssr

https://github.com/tskweres/angularfire-ssr-test

** make sure to input your own firebaseConfig in the environments

In the app.component.ts, you'll see that I inject AngularFireStore, and then make a query on a collection.

The query completes and the console logs the result, but when launching the browser in chrome, the web page never renders.

If I do not make the this.db.collection('.....') call, the web page renders.

Any ideas?

tskweres commented 4 years ago

It's almost as if AngularFire makes the query call, but it doesn't fire next() or some sort of interceptor issue? Ultimately the html doesn't get rendered to Chrome, but there's no error

jamesdaniels commented 4 years ago

That sounds like a Zone.js issue. Note your on RC, give 6.0.0 final a shot. In the meantime I'll look at your repo, looping back to wrapping 6.0.1 shortly in which I'm aiming to button up a lot of these issues.

tskweres commented 4 years ago

@jamesdaniels Cool I appreciate it. I've tried with 6.0.0.rc-2 and 6.0.0, same issue. You can check the repo, but here's my package.json:

{
  "name": "universal-starter-v9",
  "version": "0.1.0",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/angular/universal-starter.git"
  },
  "contributors": [
    "AngularClass <hello@angularclass.com>",
    "PatrickJS <patrick@angularclass.com>",
    "Jeff Whelpley <jeff@gethuman.com>",
    "Jeff Cross <crossj@google.com>",
    "Mark Pieszak <mpieszak84@gmail.com>",
    "Jason Jean <jasonjean1993@gmail.com>",
    "Fabian Wiles <fabian.wiles@gmail.com>",
    "Kamil Mysliwiec <mail@kamilmysliwiec.com>",
    "Michael Prentice <michael.prentice@devintent.com>"
  ],
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "dev:ssr": "ng run universal-starter-v9:serve-ssr",
    "serve:ssr": "node dist/universal-starter-v9/server/main.js",
    "prebuild:ssr": "ngcc",
    "build:ssr": "ng build --prod && ng run universal-starter-v9:server:production",
    "prerender": "ng run universal-starter-v9:prerender"
  },
  "pre-commit": [],
  "private": true,
  "dependencies": {
    "@angular/animations": "~9.0.0",
    "@angular/common": "~9.0.0",
    "@angular/compiler": "~9.0.0",
    "@angular/core": "~9.0.0",
    "@angular/fire": "^6.0.0",
    "@angular/forms": "~9.0.0",
    "@angular/platform-browser": "~9.0.0",
    "@angular/platform-browser-dynamic": "~9.0.0",
    "@angular/platform-server": "~9.0.0",
    "@angular/router": "~9.0.0",
    "@nestjs/common": "^6.11.6",
    "@nestjs/core": "^6.11.6",
    "@nestjs/ng-universal": "^3.0.0",
    "@nestjs/platform-express": "^6.11.6",
    "@nguniversal/common": "9.0.0",
    "@nguniversal/express-engine": "9.0.0",
    "class-transformer": "^0.2.3",
    "class-validator": "^0.9.1",
    "classlist.js": "1.1.20150312",
    "core-js": "^2.6.5",
    "firebase": "^7.13.1",
    "rxjs": "~6.5.2",
    "terser": "^4.1.2",
    "tsconfig-paths": "^3.8.0",
    "tslib": "^1.10.0",
    "zone.js": "~0.9.1"
  },
  "devDependencies": {
    "@angular-devkit/architect": "<0.900 || ^0.900.0-0 || ^9.0.0-0",
    "@angular-devkit/build-angular": "~0.900.1",
    "@angular/cli": "~9.0.1",
    "@angular/compiler-cli": "~9.0.0",
    "@angular/language-service": "~9.0.0",
    "@grpc/proto-loader": "^0.5.4",
    "@nguniversal/builders": "^9.0.0",
    "@types/jasmine": "~3.5.3",
    "@types/jasminewd2": "~2.0.8",
    "@types/node": "~13.7.0",
    "codelyzer": "^5.2.1",
    "cpy-cli": "2.0.0",
    "express": "4.17.1",
    "firebase-tools": "^7.12.1",
    "fuzzy": "^0.1.3",
    "http-server": "0.12.1",
    "inquirer": "^6.2.2",
    "inquirer-autocomplete-prompt": "^1.0.1",
    "jasmine-core": "~3.4.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~4.4.1",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~2.1.1",
    "karma-jasmine": "~3.1.0",
    "karma-jasmine-html-reporter": "^1.5.2",
    "mini-css-extract-plugin": "^0.9.0",
    "nodemon": "^2.0.2",
    "pre-commit": "1.2.2",
    "protractor": "~5.4.3",
    "reflect-metadata": "0.1.13",
    "ts-loader": "^6.2.1",
    "ts-node": "~8.6.2",
    "tslint": "~6.0.0",
    "typescript": ">=3.6.4 <3.8.0",
    "wait-on": "^4.0.0",
    "webpack-cli": "^3.3.6",
    "ws": "^7.2.3",
    "xhr2": "^0.2.0"
  }
}

Angular.json:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "universal-starter-v9": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss"
        }
      },
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/universal-starter-v9/browser",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "universal-starter-v9:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "universal-starter-v9:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "universal-starter-v9:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "e2e/tsconfig.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "universal-starter-v9:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "universal-starter-v9:serve:production"
            }
          }
        },
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/universal-starter-v9/server",
            "main": "server.ts",
            "tsConfig": "tsconfig.server.json",
            "externalDependencies": [
              "@nestjs/microservices",
              "@nestjs/microservices/microservices-module",
              "@nestjs/websockets",
              "@nestjs/websockets/socket-module",
              "cache-manager",
              "@firebase/firestore",
              "firebase/firestore",
              "@grpc/proto-loader"
            ]
          },
          "configurations": {
            "production": {
              "outputHashing": "media",
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "sourceMap": false,
              "optimization": false
            }
          }
        },
        "serve-ssr": {
          "builder": "@nguniversal/builders:ssr-dev-server",
          "options": {
            "browserTarget": "universal-starter-v9:build",
            "serverTarget": "universal-starter-v9:server"
          },
          "configurations": {
            "production": {
              "browserTarget": "universal-starter-v9:build:production",
              "serverTarget": "universal-starter-v9:server:production"
            }
          }
        },
        "prerender": {
          "builder": "@nguniversal/builders:prerender",
          "options": {
            "browserTarget": "universal-starter-v9:build:production",
            "serverTarget": "universal-starter-v9:server:production",
            "routes": [
              "/"
            ]
          },
          "configurations": {
            "production": {}
          }
        },
        "deploy": {
          "builder": "@angular/fire:deploy",
          "options": {}
        }
      }
    }
  },
  "defaultProject": "universal-starter-v9",
  "cli": {
    "analytics": false
  }
}
n3nikita commented 4 years ago

I think my issue is related to this. #2416 Do you get timeout error?

I'm creating working repo with my problem from scratch now.

tskweres commented 4 years ago

No timeout error, the chrome page still remains it its 'loading' state with the 'X' in the top left, but no server errors, no webpage render

rogervanwile commented 4 years ago

@tskweres : Do you have a workaround right now? I have the same issue in my project and invested hours of debugging, but have no idea how to solve it. I'm not that familiar with zone.js.

Btw. I can reproduce this issue with Angular 8 and Angular Fire 5.4.2

Angular CLI: 8.3.25
Node: 10.19.0
OS: darwin x64
Angular: 8.2.13
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... platform-server, router

Package                                    Version
--------------------------------------------------------------------
@angular-devkit/architect                  0.802.2
@angular-devkit/build-angular              0.803.25
@angular-devkit/build-ng-packagr           0.802.2
@angular-devkit/build-optimizer            0.803.25
@angular-devkit/build-webpack              0.803.25
@angular-devkit/core                       8.2.2
@angular-devkit/schematics                 8.3.25
@angular/cdk                               8.2.3
@angular/cli                               8.3.25
@angular/fire                              5.4.2
@angular/material                          8.2.3
@ngtools/webpack                           8.3.25
@nguniversal/express-engine                8.2.6
@nguniversal/module-map-ngfactory-loader   8.1.1
@schematics/angular                        8.3.25
@schematics/update                         0.803.25
ng-packagr                                 5.7.1
rxjs                                       6.5.3
typescript                                 3.5.3
webpack                                    4.39.2
tskweres commented 4 years ago

I don't, waiting on 6.0.1 :(

Continuing to code running the app on the front-end until the fix is out

n3nikita commented 4 years ago

I've checked today. I also have infinity loading when call this.db.collection('.....'). I'll try to reproduce this issue with Angular 9. Will update soon

rogervanwile commented 4 years ago

@tskweres, @n3nikita : Which versions of the Firebase SDK are you using? I just tried to downgrade to an older version, in my case from 7.14.1 to 7.0.0. And now it seems that the rendering is working.

Was only working on local SSR, not on Firebase Functions SSR. :(

n3nikita commented 4 years ago

@tskweres I've found that I face this problem when I trying to get only one item by id from the database.

Examples:

Articles page I get all my articles by several parameters. It loads well and I don't have any errors.

this.db.collection('articles', ref => ref.orderBy('date', 'desc')
                                        .where('status', '==', status)
                                        .startAfter(last.date)
                                        .limit(count))
      .valueChanges({ idField: 'id' }).subscribe(articles => {
        this.updateSubjectByStatus(status, articles as Article[], isPush);
      });

Article page I'm trying to get only one article by Id. This method works before but after update to Angular 9 and adding SSR I get an infinity loading.

return this.db.doc('articles/' + id)
      .snapshotChanges()
      .pipe(
        take(1),
        map(doc => {
          return {
            id: doc.payload.id,
            ...(doc.payload.data() as object) 
          } as Article;
        }));

I changed my method by the following one and page seems to be working fine. Infinity loading gone.

return this.db.collection('articles').doc(id).valueChanges();
n3nikita commented 4 years ago

I also use the AuthService at my component and when I subscribe to authState I face this problem.

My auth.service.ts file:

export class AuthService {
  constructor(
    private authFire: AngularFireAuth) {
  }

  isAuth() {
    return this.authFire.authState;
  }
}

This is how I call isAuth() at my component:

this.authService.isAuth().subscribe(data => {
    this.user = data;
});

when I comment this code page loads well

tskweres commented 4 years ago

@n3nikita @rogervanwile

FYI:

  1. I tried testing the .doc vs .collection methods, same issue.
  2. I tried wrapping the AngularFirestore calls in Zone.run, still the same issue
  3. I tried installing firebase 7.0.0, but it created a bunch of other errors so I went back to @latest
urish commented 4 years ago

Same issue here, fixed by downgrading back to 5.2.3

tskweres commented 4 years ago

@urish can you post your package.json?

I try running with @angular/fire 5.2.3, but it breaks AngularFireAuth, I'm assuming AngularFireAuth changed between 5.2.3 -> 6

urish commented 4 years ago

Yes, you need to add .auth before any calls to signInWithPopup(), e.g.

this.afa.signInWithPopup(new firebase.auth.GoogleAuthProvider());

turns into

this.afa.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());

and possibly other methods

tskweres commented 4 years ago

@urish And what is the import at the top? Can I import AngularFireAuth?

urish commented 4 years ago

Yes, it hasn't changed

tskweres commented 4 years ago

@urish I appreciate the help here, still working through errors introduced by rolling back.

Any idea how to avoid this one?

Error: Uncaught (in promise): TypeError: app.firestore is not a function

tskweres commented 4 years ago

Tried removing node_modules and package-lock.json and re-installing, still there though, must be a version of one of the other packages

urish commented 4 years ago

I had to apply the following patch to fix this:

diff --git a/node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/server.js b/node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/server.js
index d1c0a61..e74af64 100644
--- a/node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/server.js
+++ b/node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/server.js
@@ -40,7 +40,7 @@ function getServerConfig(wco) {
         node: false,
     };
     if (bundleDependencies) {
-        config.externals = [...externalDependencies];
+        config.externals = [...externalDependencies, /^firebase/];
     }
     else {
         config.externals = [
tskweres commented 4 years ago

I tried Angularfire at 5.2.3 and applied the fix you mentioned, but the original error of no web page rendering still persists. Here's my package.json

{
  "name": "testapp-web",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "dev:ssr": "ng run testapp-web:serve-ssr",
    "serve:ssr": "node dist/testapp-web/server/main.js",
    "build:ssr": "ng build --prod && ng run testapp-web:server:production",
    "prerender": "ng run testapp-web:prerender"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^9.0.7",
    "@angular/common": "~9.1.2",
    "@angular/compiler": "~9.1.2",
    "@angular/core": "~9.1.2",
    "@angular/fire": "5.2.3",
    "@angular/forms": "~9.1.2",
    "@angular/platform-browser": "~9.1.2",
    "@angular/platform-browser-dynamic": "~9.1.2",
    "@angular/platform-server": "~9.1.2",
    "@angular/router": "~9.1.2",
    "@grpc/proto-loader": "^0.5.4",
    "@nguniversal/express-engine": "^9.0.2",
    "@types/googlemaps": "^3.39.3",
    "bulma": "^0.8.1",
    "express": "^4.15.2",
    "firebase": "^7.14.2",
    "fsevents": "^2.1.2",
    "lodash.throttle": "^4.1.1",
    "ngx-google-places-autocomplete": "^2.0.4",
    "ngx-toastr": "^12.0.0",
    "rxjs": "~6.5.4",
    "rxjs-compat": "^6.5.5",
    "tslib": "^1.10.0",
    "zone.js": "~0.10.2"
  },
  "devDependencies": {
    "@angular-devkit/architect": "^0.900.0-0 || ^0.900.0",
    "@angular-devkit/build-angular": "~0.901.2",
    "@angular/cli": "~9.1.2",
    "@angular/compiler-cli": "~9.1.2",
    "@angular/language-service": "~9.1.2",
    "@nguniversal/builders": "^9.0.2",
    "@types/express": "^4.17.0",
    "@types/jasmine": "~3.5.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "^12.11.1",
    "bufferutil": "^4.0.1",
    "codelyzer": "^5.1.2",
    "domino": "^2.1.4",
    "firebase-tools": "^7.12.1",
    "fuzzy": "^0.1.3",
    "inquirer": "^6.2.2",
    "inquirer-autocomplete-prompt": "^1.0.1",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~4.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~2.1.0",
    "karma-jasmine": "~2.0.1",
    "karma-jasmine-html-reporter": "^1.4.2",
    "protractor": "~5.4.3",
    "ts-node": "~8.3.0",
    "tslint": "~5.18.0",
    "typescript": "~3.7.5",
    "utf-8-validate": "^5.0.2",
    "ws": "^7.2.3",
    "xhr2": "^0.2.0"
  }
}

Just gonna stick with the latest of everything I suppose, hopefully 6.0.1 fixes it soon

kshkrao3 commented 4 years ago

I am facing the same issue here. I tried to keep console logs in my initial components to see if I can make out anything that breaks in between, but no use. I ran a simple universal application without angular fire and it works very fine. But this is causing an infinite loading issue. I am out of options. Below is my package.json in case anyone has any idea to resolve this.

"dependencies": {
    "@agm/core": "^1.1.0",
    "@agm/snazzy-info-window": "^1.1.0",
    "@angular/animations": "~9.1.3",
    "@angular/cdk": "^9.2.1",
    "@angular/common": "~9.1.3",
    "@angular/compiler": "~9.1.3",
    "@angular/core": "~9.1.3",
    "@angular/fire": "^6.0.0",
    "@angular/forms": "~9.1.3",
    "@angular/localize": "9.1.3",
    "@angular/platform-browser": "~9.1.3",
    "@angular/platform-browser-dynamic": "~9.1.3",
    "@angular/platform-server": "~9.1.3",
    "@angular/router": "~9.1.3",
    "@ks89/angular-modal-gallery": "^7.3.0-rc.1",
    "@ng-bootstrap/ng-bootstrap": "^6.1.0-beta.2",
    "@nguniversal/express-engine": "^9.1.0",
    "@nguniversal/module-map-ngfactory-loader": "9.0.0-next.9",
    "angular-count-to": "0.0.3",
    "angular-tilt": "^1.2.0",
    "angular-typing-animation": "^0.5.4",
    "animate-scss": "^3.2.1",
    "animate.css": "^3.7.2",
    "bootstrap": "^4.4.1",
    "classlist.js": "^1.1.20150312",
    "cookieconsent": "^3.1.1",
    "core-js": "^3.6.5",
    "express": "^4.17.1",
    "firebase": "^7.14.2",
    "firebaseui": "4.5.0",
    "firebaseui-angular": "^4.1.0",
    "jspdf": "^1.5.3",
    "jspdf-autotable": "^3.4.4",
    "lodash": "4.17.15",
    "moment-timezone": "^0.5.28",
    "mousetrap": "^1.6.5",
    "ng-animate": "^0.3.4",
    "ng2-animate-on-scroll": "^2.0.0",
    "ng2-cookies": "^1.0.12",
    "ng2-scroll-to-el": "^1.2.1",
    "ng5-slider": "^1.2.4",
    "ngx-build-plus": "^9.0.6",
    "ngx-content-loading": "^0.1.3",
    "ngx-cookieconsent": "^2.2.3",
    "ngx-logger": "^4.1.9",
    "ngx-masonry": "^9.1.1",
    "ngx-masonry-gallery": "^3.0.0",
    "ngx-owl-carousel-o": "^3.0.0",
    "ngx-spinner": "^9.0.2",
    "ngx-swiper-wrapper": "^9.0.1",
    "ngx-toastr": "^12.0.1",
    "razorpay": "^2.0.6",
    "rxjs": "^6.5.5",
    "rxjs-compat": "^6.5.5",
    "snazzy-info-window": "^1.1.1",
    "sweetalert2": "^9.10.12",
    "tslib": "^1.11.1",
    "web-animations-js": "^2.3.2",
    "zone.js": "~0.10.3"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "0.901.3",
    "@angular/cli": "^9.1.3",
    "@angular/compiler-cli": "~9.1.3",
    "@angular/language-service": "~9.1.3",
    "@types/express-serve-static-core": "^4.17.5",
    "@types/googlemaps": "^3.39.3",
    "@types/jasmine": "~3.5.10",
    "@types/jasminewd2": "~2.0.8",
    "@types/lodash": "^4.14.150",
    "@types/mousetrap": "^1.6.3",
    "@types/node": "^13.13.2",
    "bufferutil": "^4.0.1",
    "codelyzer": "^5.2.2",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~5.0.2",
    "karma": "~5.0.2",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~2.1.1",
    "karma-jasmine": "~3.1.1",
    "karma-jasmine-html-reporter": "^1.5.3",
    "localstorage-polyfill": "^1.0.1",
    "protractor": "~5.4.4",
    "replace-in-file": "^5.0.2",
    "serverless-webpack": "^5.3.1",
    "ts-loader": "^7.0.1",
    "ts-node": "~8.9.0",
    "tslint": "~6.1.1",
    "typescript": "^3.8.3",
    "utf-8-validate": "^5.0.2",
    "webpack-cli": "^4.0.0-beta.8",
    "ws": "^7.2.3",
    "xhr2": "^0.2.0"
  }
n3nikita commented 4 years ago

@tskweres You can check my Angular 9 Universal + Firebase sample project angular-universal-firebase. It seems to be working with the following code:

return this.db.collection('articles').doc(id).valueChanges();

but there's still infinity loading when I try get an authState.

kshkrao3 commented 4 years ago

@tskweres You can check my Angular 9 Universal + Firebase sample project angular-universal-firebase. It seems to be working with the following code:

return this.db.collection('articles').doc(id).valueChanges();

but there's still infinity loading when I try get an authState.

But honestly, do we need auth to work in server? I mean you just need to present it in client end right? My current solution which I am following is to check whether I am on server with isPlatformBrowser(plaformId) and then render auth functionality in client and skip it on server. That way it will come onto client and render it without the infinity loading.

But unfortunately, I had to skip all my db calls for now. Not sure what's wrong with the db calls. I have below:

httpDataService.ts

getCategoryMenu(): Observable<MenuItems> {
    return this.afs.collection('collection').doc<MenuItems>('menuitems').valueChanges();
}

Then in my component, I would do as below:

this.categories = this.httpDataService
      .getCategoryMenu()
      .pipe(takeUntil(this.subs$))
      .map((res) => {
        const menuData = res.items;
        const itemShuffled = shuffle(menuData).splice(0, 6);
        return itemShuffled.map((menu) => {
          const menuArr = { title: '', category: '' };
          menuArr.title = menu.name;
          menuArr.category = kebabCase(menu.slug);
          return menuArr;
        });
      });

In my case, I suspect that rxjs and lodash methods are not working in ssr. Any pointers anyone?

tskweres commented 4 years ago

@jamesdaniels Definitely some crazy RxJS stuff going on. I found it works if:

  1. remove all observable pipes, not allowed to pipe anything
  2. Must be running v. 9.0 of angular modules, 9.1+ breaks it
    "@angular/animations": "~9.0.0",
    "@angular/common": "~9.0.0",
    "@angular/compiler": "~9.0.0",
    "@angular/core": "~9.0.0",
    "@angular/fire": "^6.0.0-canary.9e19b14",
    "@angular/forms": "~9.0.0",
    "@angular/platform-browser": "~9.0.0",
    "@angular/platform-browser-dynamic": "~9.0.0",
    "@angular/platform-server": "~9.0.0",
    "@angular/router": "~9.0.0",

Hope that helps!

n3nikita commented 4 years ago

@kshkrao3 Thank you for the solution. I call auth only at browser and infinity loading gone.

kshkrao3 commented 4 years ago

@n3nikita Tell me something, do you use rxjs operators on the firestore data and still it works, or you are just manipulating plain db documents to display in frontend?

n3nikita commented 4 years ago

@n3nikita Tell me something, do you use rxjs operators on the firestore data and still it works, or you are just manipulating plain db documents to display in frontend?

When I use the following code I get an infinity loading:

getById(id: string): Observable<Book> {
  return this.db.doc('books/' + id)
      .snapshotChanges()
      .pipe(
        take(1),
        map(doc => {
          return {
            id: doc.payload.id,
            ...(doc.payload.data() as object)
          } as Book;
        }));
}

so I changed my code to the following:

getById(id: string): Observable<Book> {
    return this.db.collection('books').doc<Book>(id).valueChanges();
}

I think the problem might be connected with rxjs operators.

tbacon1991 commented 4 years ago

Any update on this I cannot get the Firebase functions to deploy using Firestore. I have tried everything mentioned in this thread with no avail. Pointless evening using Firebase if this doesn't work.

kshkrao3 commented 4 years ago

@tbacon1991 .. As for now, we are waiting for the v6.0.1 and hopefully it resolves these issues. Bdw, what's the error you are getting?

tbacon1991 commented 4 years ago

@kshkrao3 Hopefully comes soon pretty big piece to the puzzle, for now I have copied by database to local and will be making updates via local HTTP requests, any changes admin have have to come via me for the moment. Relatively small so not a huge issue but still flipping annoying.

My main error was/is: Detailed stack trace: Error: Cannot find module '@firebase/app'

I have tried installing Firebase in the functions folder, providing it as an external dependency etc as mentioned in the thread. Tried all different versions but still getting the same error. If the full error is is needed I can try and dig it out.

kshkrao3 commented 4 years ago

Could you please paste your app package.json, angular.json and functions package.json? Let's see if you miss anything.

ValentinFunk commented 4 years ago

Might have found a fix for this, basically:

image

image

Would do a MR but unfortunately we're not yet on Angular 9. Did a small repository to try and replicate this with the realtime database the other day and also got Zone issues when forking out, e.g.

    this.trips$ = this.db.list('/fav-ids').snapshotChanges().pipe(
      switchMap(featured => combineLatest(
        featured.map(id => this.db.object(`stories/${id.payload.exportVal()}`).snapshotChanges())
      )),

With the fix it works, when stress testing I still get instabilities though when running multiple instances in parallel. This strangely happens for both, same process and also different node processes which is super weird. In production I now retry SSR by setting a timeout of 5s and if the render fails retrying. Not really optimal but I have no idea how to further debug this.

levonka commented 4 years ago

@tskweres I struggled with infinity loading problem all day. Now I tried to remove the pipe and everything works fine.

    this._db.collection<ISlide>('carousel-slides')
        .valueChanges()
        // .pipe(first())
        .subscribe((slides) => console.log('hi: ', slides));

I have not tried deploying yet, but it looks like a temporary solution to the problem.

    "@angular/core": "9.1.4",
    "@angular/fire": "6.0.0",
    "firebase": "7.14.2",
tskweres commented 4 years ago

@levonka gotcha, would be more interested to get a proper fix, I use pipes for lots of observable logic, thanks for the heads up!

FaisalChoura commented 4 years ago

I'm facing the same issue I need to pipe first() because I'm using a route resolver. removing the first() pipe works but breaks my application's logic

kshkrao3 commented 4 years ago

@davideast .. Any idea when angularfire 6.0.1 is going to release? We are stuck with this rxjs issue and this seems critical for now.. :)

rogervanwile commented 4 years ago

Why do you think that version 6.0.1 is fixing that? For me it looks like no core developer is working on this issue, or do I miss something? Does someone know, how to get a higher priority to this bug?

I am also not sure if AngularFire is causing this issue, it could also be a bug in one of the dependencies.

Detys commented 4 years ago

I'll agree on this being critical.

After a lot of hours of debugging, infinite loaders and following every comment on this thread i just managed to get it to work.

I'm currently on: '@angular/*' : 9.0.1 "@nguniversal/express-engine": 9.0.0 "firebase": "^7.14.4", "rxjs": "^6.5.5", "@angular/fire": "^6.0.0-canary.9e19b14",

Here the relative snippet of code that is causing trouble for me. It would appear that the problem has to do with subscribe

This causes infinite loader: this.post$ = this.postsService.getPost(friendlyurl); this.post$.subscribe(t =>{ this.title.setTitle(t.SeoTitle) })

This works just fine: this.post$ = this.postsService.getPost(friendlyurl).pipe(tap(t => this.title.setTitle(t.SeoTitle)));

and just for reference postsService.getPost is just: return this.db.collection('posts').doc<post>(friendlyUrl).valueChanges();

I'll try bumping the version back to 9.1.7 and see what happens.

I hope this helps.

tskweres commented 4 years ago

So you're saying removing all subscribes fixes the issue?

@jamesdaniels a new version coming soon?

Detys commented 4 years ago

So you're saying removing all subscribes fixes the issue?

@jamesdaniels a new version coming soon?

Yes, for my case at least. That did it. I've even deployed it and it works as expected

kshkrao3 commented 4 years ago

So you're saying removing all subscribes fixes the issue? @jamesdaniels a new version coming soon?

Yes, for my case at least. That did it. I've even deployed it and it works as expected

I agree that this could be the good solution. But what if we just want to subscribe to any changes in the db? kind of real-time. I think tap would not work then right?

Detys commented 4 years ago

So you're saying removing all subscribes fixes the issue? @jamesdaniels a new version coming soon?

Yes, for my case at least. That did it. I've even deployed it and it works as expected

I agree that this could be the good solution. But what if we just want to subscribe to any changes in the db? kind of real-time. I think tap would not work then right?

If you separate you code into server and client side then you should be ok. When it's for SSR you just need to take the data once. After its on the client you can use subscribe normally.

tskweres commented 4 years ago

Would love to see an update for this, it seems like writing separate subscriptions for serverside vs client defeats the purpose

tskweres commented 4 years ago

Tracked it down further - it all does stem from AngularFireAuth not working server side.

However - would love to have this working, I'd like to render the homepage with the user's avatar in the header and not have it flash because it's waiting for client side, any ideas?

ValentinFunk commented 4 years ago

@tskweres you can store a cookie with a firebase custom auth token after login, use that in SSR to log a user in so that they get a version that is rendered for their auth state (@Inject(REQUEST) the request to read the cookie and use signInWithCustomToken).

tskweres commented 4 years ago

In the end:

  1. Make sure any resolvers that return Observables complete
  2. Make sure any guards that return Observables complete
  3. AngulareFireAuth only works client side, so must check for platform
  4. Implement cookies for server side auth

All works

choenden commented 4 years ago

Why was this closed? I think a .pipe(take(1)) still breaks, as is mentioned above. Without the pipe, it works fine.

jkinger commented 4 years ago

Agreed, this thread seemed to have gotten a little sidetrack... simply try to generate a latest ng9 + AngularFire, try to use .pipe(take(1)) or .pipe(first()) and the page will never resolve. No AngulareFireAuth needed. It's really that easy to reproduce. I can push up a github sample repo if needed.

tskweres commented 4 years ago

Reopened for those still having issues