angularfire: Angular 11 Firebase Server-side rendering infinite loading / pending

Angular: 11

Firebase: 8.2.1

AngularFire: 6.1.4

How to reproduce these conditions

This works as expected in NON-SSR mode, to query once a given collection:

this.firestore.collection<T>('collection', ref => ref.limit(5))
    .get()
    .pipe(
      map((qs: firebase.firestore.QuerySnapshot) => qs.empty ? [] : qs.docs.map(d => d.data() as T)),
    );

When switching to SSR, the above code leads to the express server hanging, and the client see a ‘pending’ query that never completes, or hits a timeout and leaves the page partially rendered (i.e. without the results of that query).

This is the best workaround I found:

this.firestore.collection<T>('collection', ref => ref.limit(5))
    .valueChanges()   <<<<
    .pipe(
      take(2),        <<<<
    );

Though this more sane workaround also fails:

this.firestore.collection<T>('collection', ref => ref.limit(5))
    .valueChanges()
    .pipe(
      take(1),      <<<<
    );

More details about exact version used here: https://stackoverflow.com/questions/65388261/angular-11-firebase-server-side-rendering-infinite-loading-pending/65388376#65388376

Expected behavior

The first version should work without the workaround, without and with SSR.

Actual behavior

Without the workaround, the express server hangs indefinitely.

Related issues: https://github.com/firebase/firebase-js-sdk/issues/3541 https://github.com/firebase/firebase-js-sdk/issues/3542 https://github.com/angular/universal/issues/1711

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 21 (2 by maintainers)

Most upvoted comments

Ran into the same issue. SSR function Timeout on some routes in cloud functions. All pages that triggered a function with a .take(1) operator caused the issue. Changing it to .take(2) solved the problem. Not sure if this should be considered a bug or expected behavior. My thesis: The observable is triggered twice. Once from the SSR, once CSR. Does this make sense?

🚨This doesn’t work:

getProduct(id: string): Observable<Product> {
    const collection = this.afs.collection<Product>("Products");    
    return collection.doc<Product>(id).valueChanges().pipe(
      take(1),
      map(product => {
        product.id = id;
        return product;
      })
    );
  }

🥦This works:

getProduct(id: string): Observable<Product> {
    const collection = this.afs.collection<Product>("Products");    
    return collection.doc<Product>(id).valueChanges().pipe(
      take(2),
      map(product => {
        product.id = id;
        return product;
      })
    );
  }

take1

Just to bump this topic, I’m experiencing similar issues. I’ve read through all of these threads and tried nearly all of the workarounds suggested. None of them seem to work. I’ve been struggling with this for a couple of weeks.

In my use-case I’m using a resolver to fetch data from firebase before a page load. I’ve noticed very inconsistent results. Occasionally it’ll start working locally - but then the deployed version won’t work.

What’s interesting is the routes don’t hang if I load into the app and then navigate to them; as opposed to linking to them directly. Another thing, it seems like at times the first request to the page I’m attempting to load will work, but then all subsequent requests will fail until I clear my browser cache and try again. Very odd behavior.

Things I’ve tried:

  • Running firebase queries outside of Angular
  • Downgrading angularfire/firebase
  • Loading page content in ngOnInit instead of a resolver
  • Removing all pipes
  • Using snapshotChanges/valuesChanges
  • Adding my own AuthGuard and attaching them to the failing routes.

I’m pretty well stuck here. This is pretty frustrating, as I’m maintaining a user-facing app.

If it helps, this is the error I’m seeing in my deployed environment: Timed out while waiting on cache-bos4679-BOS

hey @jamesdaniels, omg!!! you safe my life!!! thanksssssss!!!

hey @jamesdaniels, thanks for your detailed reply. That makes sense. Not that I understand everything, but it helps a lot. Thanks again, for taking(2) time to reply. ❤️ I will experiment with it and check which is the best recipe for my usecase.

Related to getting firebase serve to work, I was able to at least get it to stop hanging by making the change below,

export const universal = functions.https.onRequest((request, response) => {
  require(`${process.cwd()}/dist/podcasts11/server/main`).app(request, response);
});

to this:

const ssr = require(path.resolve(__dirname, '../dist/podcasts11/server/main')).app();
export const universal = functions.https.onRequest(ssr);

But it still does not render server-side.

I think that you have to move angular compiled dist inside your functions folder. and deploy all as a function project.

for example: in functions tsconfig.json change da “outDir” from “lib” to “dist” change your ssr function to

` import * as functions from ‘firebase-functions’; const expressApp = require(‘./podcasts11/server/main’).app();

export const server = functions .region(‘us-central1’) .runWith({ timeoutSeconds: 60, memory: ‘1GB’ }) .https.onRequest(expressApp);

`

Move your angular compiled app folder “dist/podcasts11” inside “functions/dist” and your firebase public folder should be “public”: “functions/dist/podcasts11/browser”,

then you can deploy and it will works.

I had this issue months ago and i resolved doing this changes.