我在使用快速服务器构建和提供 Angular Universal 应用程序以获得良好的 SEO 方面遇到了挑战。
当我使用带有命令 "dev:ssr": "ng run motif:serve-ssr"
的脚本为其提供服务时并在浏览器上访问它的默认端口 4200
并使用 Chrome 的查看页面源代码选项查看源代码,我可以看到正确的动态元标记以及 HTML 源代码,效果非常好。
但是当我使用以下命令构建和提供它时,元标记没有被更新
"build:ssr": "ng build --prod && ng run motif:server:production"
npm run build:ssr && npm run serve:ssr
它构建和呈现没有错误,但是当我在 Chrome 上查看页面源代码时,我只看到为 index.html
设置的元标记文件,但我希望它为每个文章数据设置标签,如页面标题、描述、图像等。我正在路由器数据解析器服务中设置元标记,它工作正常,因为我可以在运行 dev:ssr 脚本时看到它的工作。
CLI 版本是 9.1.12(v10 和 11v 有 ssr 和 window 对象的问题)。我是否遗漏了什么或做错了什么?
我很感激对此问题的任何建议和解决方案。
更新:
数据解析器的简化版本如下:
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { DomSanitizer, TransferState } from '@angular/platform-browser';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { SeoSocialShareData, SeoSocialShareService } from 'ngx-seo';
import { Observable, of, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class ArticleDataResolver implements Resolve<any> {
constructor(
private seoSocialShareService: SeoSocialShareService,
private angularFirestore: AngularFirestore,
) { }
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any> | Promise<any> | any {
const stateKey = state.url;
const ref = this.angularFirestore.collection("movementArticles");
return ref
.doc(route.params.id)
.get()
.pipe(
map((dataSnap) => {
const seoData: SeoSocialShareData = {
title: '...',
description: '...',
image: '...',
author: '...',
keywords: `...`,
url: `...`,
published: '...',
};
this.seoSocialShareService.setData(seoData);
return dataSnap;
})
);
}
}
最佳答案
我与您分享这项服务
如果您不需要翻译,可以省略翻译服务
并尝试调用 中的方法构造函数或 ngOnInit 你的组件 View
import { Injectable } from '@angular/core';
import { Title, Meta } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class SEOService {
constructor(private title: Title, private meta: Meta, private translate: TranslateService) {}
async getTranslation(word: string) {
if (word) {
return await this.translate
.get(word)
.toPromise()
.then(resp => {
return resp;
});
} else {
return '';
}
}
async updateTitle(title: string) {
const translation = await this.getTranslation(title);
this.title.setTitle(translation);
}
async updateDescription(desc: string) {
const translation = await this.getTranslation(desc);
this.meta.updateTag({ name: 'description', content: translation });
}
async updateKeywords(keywords: string) {
const translation = await this.getTranslation(keywords);
this.meta.updateTag({ name: 'keywords', content: translation });
}
async updateOgUrl(url: string) {
const translation = await this.getTranslation(url);
this.meta.updateTag({
name: 'og:url',
property: 'og:url',
content: translation
});
}
async updateOgTitle(ogTitle: string) {
const translation = await this.getTranslation(ogTitle);
this.meta.updateTag({
name: 'og:title',
property: 'og:title',
content: translation
});
}
async updateOgDescription(ogDesc: string) {
const translation = await this.getTranslation(ogDesc);
this.meta.updateTag({
name: 'og:description',
property: 'og:description',
content: translation
});
}
async updateOgImage(ogImg: string) {
const translation = await this.getTranslation(ogImg);
this.meta.updateTag({
name: 'og:image',
property: 'og:image',
content: translation
});
}
async disableFollow() {
this.meta.addTag({
name: 'robots',
property: 'robots',
content: 'noindex, nofollow'
});
}
async enableFollow() {
this.meta.removeTag('robots');
}
}
全局 ngOnInit 示例
import { Component, OnInit } from '@angular/core';
import {
Router,
NavigationEnd,
ActivatedRoute,
RouterEvent
} from '@angular/router';
export class AppComponent implements OnInit {
constructor(
private router: Router,
private route: ActivatedRoute,
private seoService: SEOService,
) {
}
ngOnInit() {
this.router.events
.pipe(
filter(event => event instanceof NavigationEnd),
map(() => this.route),
map(route => {
while (route.firstChild) {
route = route.firstChild;
}
return route;
}),
filter(route => route.outlet === 'primary'),
mergeMap(route => route.data)
)
.subscribe(event => {
this.seoService.updateTitle(event['title']);
this.seoService.updateDescription(event['description']);
this.seoService.updateKeywords(event['keywords']);
this.seoService.updateOgUrl(event['url']);
this.seoService.updateOgTitle(event['ogTitle']);
this.seoService.updateOgDescription(event['ogDesc']);
this.seoService.updateOgImage(event['ogImage']);
});
}
}
希望这可以帮到你 ;)
关于angular - 使用 Angular 通用开发 :ssr works but build:ssr is not working 设置页面元标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66925705/