Мета-теги Angular9 SSR не загружаются внутри обещаний - PullRequest
0 голосов
/ 28 мая 2020

Я использую Angular Universal и Nest JS для моего SSR. Когда я запускаю npm run build:ssr и развертываю его, я не получаю ошибок, но метатеги внутри обещаний не отображаются при связывании веб-сайта, но ссылки для маршрутов, для которых я установил метатеги на уровне root ngOnInit, загружают метатеги, как и ожидалось, при связывании веб-сайта.

Код для установки метатегов.

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' },
 ]);
} 

Пример кода, который не загружает метатеги

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,
  })
})

Пример кода, который не загружает метатеги

this.seo.generateTags({
  title: userRef.data().displayName,
  description: userRef.data().about,
  image: userRef.data().photoURL,
})

Пример с полным компонентом:

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,
      })
    })
  }
}

Кто я могу отображать контент, например, из firebase, в моих метатегах с Angular9 с Nest JS?

I создали фиктивный проект на GitHub, где я получаю эту ошибку. Чтобы воспроизвести, прикрепите проект firebase в файл среды и запустите npm run serve:ssr (возможно, npm run build:ssr, если вы получите сообщение об ошибке) и увидите в исходном коде в chrome, что метатеги не отображаются.

EDIT : Я попытался решить эту проблему с помощью метода resolve, но он по-прежнему не работает с обещаниями. Это сценарий разрешения, который я использую:

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();
  }
}

Код, который я использую в своем компоненте:

this.route.data.subscribe(data => {
  console.log(data.cres)

  this.seo.generateTags({
    title: data.cres,
    description: data.cres,
    image: data.cres,
  })
});

Ответы [ 3 ]

3 голосов
/ 03 июня 2020

Angular SSR ждет, пока все обещания не закончатся sh в ngInit (), прежде чем отправить ответ пользователю. Но я обнаружил, что ngInit не ждал, используя метод get () хранилища огня. Итак, я связался с valueChanges (), и он работает так, как ожидалось, и еще одна хорошая вещь заключается в том, что он сразу возвращает Observable с данными, поэтому ваш ngInit будет выглядеть так:

ngOnInit() {
    this.customerId = this.route.snapshot.paramMap.get('id');

    this.db.collection('users').doc(this.customerId).valueChanges().subscribe(user => {
      this.seo.generateTags({
        title: user.displayName,
        description: user.about,
        image: user.photoURL,
      });
    });
  }

Еще одна вещь, которую вы можете найти полезно использовать TransferState для передачи того, что сервер разрешил, в браузер, чтобы он не пытался получить информацию еще раз, когда браузер полностью загружает страницу. Таким образом, ваш компонент будет выглядеть примерно так:

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';
import { TransferState, makeStateKey } from '@angular/platform-browser';


const USER_TAGS_KEY = makeStateKey('ProfileviewerComponent_UserTagsState');

@Component({
  selector: 'app-profileviewer',
  templateUrl: './profileviewer.component.html',
  styleUrls: ['./profileviewer.component.css']
})
export class ProfileviewerComponent implements OnInit {

  customerId: string;
  tags = [];

  constructor(
    private route: ActivatedRoute,
    private db: AngularFirestore,
    private state: TransferState,
    private seo: SeoService) { }

  ngOnInit() {
    this.customerId = this.route.snapshot.paramMap.get('id');

    this.tags = this.state.get(USER_TAGS_KEY, null);
    if (!this.tags) {
      this.db.collection('users').doc(this.customerId).valueChanges().subscribe(user => {
        this.tags = {
          title: user.displayName,
          description: user.about,
          image: user.photoURL,
        };

        this.state.set(USER_TAGS_KEY, this.tags);
        this.seo.generateTags(this.tags);
      });
    }
  }
}
0 голосов
/ 02 июня 2020

Наконец, после долгих исследований и отладки я выяснил, почему вы не видите метатеги в своем индексе. html.

  1. Убедитесь, что ваши метатеги добавляются. Я напечатал мета-объект в консоли после добавления тегов. Вы также можете это проверить. Распечатайте его: - в выводе go под _do c> documentChild> inner Html

enter image description here

На изображении выше в inner HTML, вы можете заметить свои метатеги.

Теперь, почему они не были частью index. html, когда он отображался, потому что обещание firebase будет автоматически разрешено, когда оно подключится к firebase и получит данные. Но поскольку это часть вашего. Ваш ssr не будет генерировать теги. Эти теги будут добавлены позже динамически, когда ваше решение будет разрешено. Любая вещь, которая изменяется после загрузки страницы, которая не будет отображаться в источнике просмотра страницы. Если вы хотите проверить обновленные метатеги, вам нужно проверить элемент и проверить там .

Чтобы доказать мою вторую точку зрения, вот скриншот файла на сетевой вкладке индекса. html.

enter image description here

и есть снимок экрана инспектора элементов, показывающий, что ваши метатеги были добавлены успешно, но во время выполнения.

enter image description here

Если вы создадите обычное обещание и внутри этого вызова метода генерации тегов он будет отображаться в самом источнике, потому что вы разрешите это обещание только там. Но в случае firebase это обещание не выполняется до тех пор, пока данные не будут получены, поэтому ваш ssr не учитывает его предварительно.

Чтобы включить firebase с ssr, вы можете найти информацию здесь: -

https://medium.com/@antonybudianto / server-side-rendering-with-react-and-firebase-functions-cd67fdb2b605

0 голосов
/ 31 мая 2020

Ваш вызов firestore - asyn c, поэтому SSR завершается до выполнения обещания. Все функции asyn c должны быть разрешены на уровне маршрутизатора, поэтому angular ожидает их завершения.

Попробуйте добавить запрос firestore в резолвер маршрутов и используйте данные из резолвера внутри ngOnInit () функция.

подробнее см. здесь: https://angular.io/api/router/Resolve

...