I’m using Angular Universal and NestJS for my SSR. When I run npm run build:ssr
and deploy it I get no errors, but the meta tags inside of promises are not shown when linking the website, but links for routes where I set the meta tags at the root level of ngOnInit do load the meta tags as expected when linking the website.
Code for setting meta tags.
generateTags({ title = '', description = '', image = '' }) {
this.title.setTitle(title);
this.meta.addTags([
// Open Graph
{ name: 'og:url', content: `https://firestarter.fireship.io${this.router.url}` },
{ name: 'og:title', content: title },
{ name: 'og:description', content: description },
{ name: 'og:image', content: image },
// Twitter Card
{ name: 'twitter:card', content: 'summary' },
{ name: 'twitter:site', content: '@fireship_dev' },
]);
}
Eksample of code that does not load the meta tags
this.db.firestore.collection('users').doc(this.customerId).get().then((userRef) => {
this.seo.generateTags({
title: userRef.data().displayName,
description: userRef.data().about,
image: userRef.data().photoURL,
})
})
Example of code that does not load the meta tags
this.seo.generateTags({
title: userRef.data().displayName,
description: userRef.data().about,
image: userRef.data().photoURL,
})
Example with full component:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { AngularFirestore } from '@angular/fire/firestore';
import { SeoService } from 'src/app/services/seo.service';
@Component({
selector: 'app-profileviewer',
templateUrl: './profileviewer.component.html',
styleUrls: ['./profileviewer.component.css']
})
export class ProfileviewerComponent implements OnInit {
customerId: string;
constructor(
private route: ActivatedRoute,
private db: AngularFirestore,
private seo: SeoService) { }
ngOnInit() {
this.customerId = this.route.snapshot.paramMap.get('id');
this.db.firestore.collection('users').doc(this.customerId).get().then((userRef) => {
this.seo.generateTags({
title: userRef.data().displayName,
description: userRef.data().about,
image: userRef.data().photoURL,
})
})
}
}
Who can I display content from e.g firebase in my meta tags with Angular9 with NestJS?
I have made a dummy project on GitHub where I get this error. To reproduce attach firebase project in the environments file and run npm run serve:ssr
(maybe npm run build:ssr
if you get an error) and see in the source code in chrome that the meta tags are not rendered.
EDIT:
I have tried using resolve to fix this issue, but it still doesn’t work with promises. This is the resolve script that I use:
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Http } from '@angular/http';
@Injectable({
providedIn: 'root'
})
export class LoadSeoService implements Resolve<any> {
constructor (private http: Http, private db: AngularFirestore) {
}
resolve (route: ActivatedRouteSnapshot, rstate: RouterStateSnapshot) {
// Works
return "test"
// Does not work
// return this.db.firestore.collection("articles").doc(route.params['id'].substr(route.params['id'].length - 20)).get();
}
}
The code I use in my component:
this.route.data.subscribe(data => {
console.log(data.cres)
this.seo.generateTags({
title: data.cres,
description: data.cres,
image: data.cres,
})
});
3
Answers
Your call to firestore is async so SSR finishes before the promise resolves. All async functions need to be resolved on router level so angular waits for them to be finished.
Try adding the firestore request to a route resolver and use the data from resolver inside the ngOnInit() function.
see more infos here: https://angular.io/api/router/Resolve
Finally, after lot of research and debugging i found out why were you not seeing meta tags in your index.html.
in output go under _doc>documentChild>innerHtml
In the image above in innerHTML, you can notice your meta tags.
To prove my 2nd point, here is screenshot of file in network tab of index.html.
and there is screenshot of element inspector showing that your meta tags were added successfully but on runtime.
If you will create a normal promise and inside that call your generate tags method, it will be showing in source itself, because you will resolve that promise there only. But in case of firebase, that promise is not resolved until data is fetched, hence your ssr coun’t pre-render it.
To enable firebase with ssr, you can find info here :-
https://medium.com/@antonybudianto/server-side-rendering-with-react-and-firebase-functions-cd67fdb2b605
Angular SSR waits until all the promises finish in ngInit() before it sends the response to the user. But I found that ngInit wasn’t waiting using the firestore’s get() method. So I tied with valueChanges() and it does work as expected and another good thing is that it returns an Observable with the data straight away, so your ngInit would look like:
Another thing you might find useful is to use TransferState to transfer what the server had resolved to the browser so it doesn’t try to get the information once again when the browser fully loads the page. So your component would end up being something like: