Angular Universal:SPA和SEO的好帮手

2019 年 6 月 14 日 前端之巅

源自 | 2muchcoffee
译者 | 王强

很多开发社区都在讨论 Angular 6(详见下方链接)的话题,在社区还能找到诸如如何构建客户端应用,或如何创建对 SEO 友好的用户界面等问题的答案。不过很多人没想到的是,最近最引人注目的新事物是在服务器端诞生的。

Angular Universal就是这样的一项革命性技术。它的宗旨是帮助开发者开发全新一代 Web 应用和 Angular 移动应用(详见下方链接)。本文将重点介绍它的各项功能!

相关链接:

Angular 6: https://2muchcoffee.com/blog/angular-6-features/

Angular 移动应用: https://2muchcoffee.com/mobile-app-development

单页应用(SPA)的优势

在 IT 行业,Angular 是广为人知的框架技术,而单页应用也一样很出名。其实 Angular 单页应用有很多潜在优势,诸如:

  • 更流畅、速度更快的 UI,因为 Angular 单页应用中大多数 HTML+CSS+Script 资源都是一次性加载完的。之后,只有在渲染页面部分必要数据时才会被载入,这具体取决于用户的操作。

  • Angular 的 SPA 是作为客户端技术运行的,HTML 页面是静态的,而所有动态修改都发生在浏览器中。在早期的 PHP 中,JSP 和 HTML 都与服务器端逻辑混在了一起,它是在服务器上生成的,所以服务器需要处理更多负载。

总之,我们可以很容易地证明单页应用(SPA)提供了很出色的用户界面性能,并带来了很好的用户体验!

既然 SPA 有这么多好处,提供了这么高质量的用户体验,你肯定会问为什么它没有广泛普及呢?下面就是它的一些局限。

Angular中的SPA:缺点

首先,搜索引擎无法确定网页到底是已准备好渲染呢,还是还没有渲染完毕。例如,SPA 还没加载完或者渲染完的时候搜索引擎就没法获取整个 HTML。只有在 MVC 都开始工作后页面才准备好让搜索引擎渲染其数据。

这里的麻烦在于搜索引擎得挑对时间开始扫描,或者知道什么时候渲染工作结束;否则引擎很可能会索引一些不完整的内容。

此外,SPA 深度链接索引起来比较复杂,这也是是 SPA 与搜索引擎相性不佳的另一大因素。

SPA 还缺少对浏览器中 HTML5 历史记录的支持,只能用其他方法替代,例如用来在 URL 之间跳转的 HTML 书签锚点 (/main#section2)。尽管搜索引擎很难分开索引页面,但想要做到这一点也有一些办法。只是相比这些绕弯子的办法来说,纯 HTML 还是更省事。

此外,SPA 的性能表现还是个问题,例如它的初始加载就很慢。众所周知,HTML 解决方案在好些指标上都比 SPA 强,速度就是其中之一(移动平台尤其明显);因为 SPA 要处理大量 JS 数据,所以启动很慢。

谷歌为SPA带来的改进

一个好消息是谷歌改进了索引单页应用的方法,所以上面提到的两个缺陷已经不复存在了。此外,在微软官方带头下,人们开始抛弃 IE9,这也让大多数平台上的 HTML5 历史可用性得到了提升。

现在还可以应用”/main/section2“这类简单 URL,所以不用强制实现 URL 锚点了。

当然,这对 SPA 的发展有很大助力。但我们还应该考虑其他主流搜索引擎的情况,例如在中国流行的百度,或者美国人喜爱的必应、雅虎等。

的确这些改进看起来并不足以为 SPA 吸引太多忠实粉丝,但也不用那么失望。对于单页应用来说,仍然有一种方法可以在浏览、优化和 SEO 性能之间取得平衡,它就是 Angular Universal。

Angular Universal对SEO的意义

简而言之,Angular Universal 让开发者可以创建速度快、互动内容丰富且对 SEO 友好的网站,同时充分利用单页应用的所有优势。

服务器端渲染意味着什么

Angular Universal 不仅能在服务器端提供标记渲染,还能提供一个简化版的 Angular 在前端生成所需的 HTML。这样一来你就能获得一个 Angular SEO 友好的单页应用,而且它会从服务器获取主要的 HTML 负载,缩短启动时间。

用户使用Angular SPA页面时

从渲染初始 HTML 到 Angular 作为 SPA 开始工作之间有一段延迟。如果用户在 Angular 接管之前就触发了什么事件的话,现在 Angular Universal 也有办法应对了:它会记录下服务器渲染的事件,然后等客户端 SPA 就绪后在客户端执行事件。

Angular Universal轻松入门

想要入门 Angular Universal 的话,最好的途径就是使用官方的 universal-starter(新手包)。它带有一些现成的应用,其中包括支持服务器端渲染的 express 服务器。

有一些问题是开发者使用 Angular Universal 开发第一个项目时经常遇到的。虽说“它完全是开箱即用的”,但你还是要注意一些要点。下面列举几个 Angular Universal 的实例。

在客户端和服务器上实现不同的效果

一般来说我们希望应用在客户端和服务器端执行的结果是一致的,而且不需要依赖任何 API。

但现实情况略有不同,有时候很难让代码实现上述目标。此外,我们可能希望有些操作在服务器端和客户端上有不一样的执行效果。

例如,当需要使用调用 DOM 元素的外部库时,服务器端进程无法访问浏览器内部对象,结果就会出错。比如说用 Svg.js 这个第三方库时,在 SSR(服务器端渲染)模式下构建项目时会出现一些预料之内的错误。

为了解决这个问题,我们为这个库添加了一个包装器,它检查到代码是在客户端执行时就会允许访问库方法。这样我们就可以避免在服务器端调用库方法导致的错误了。

import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
@Injectable()
export class SvgService {
private _svg: any;
constructor(@Inject(PLATFORM_ID) private platformId: Object) {
if (isPlatformBrowser(this.platformId)) {
this._svg = require('svg.js');
}
}
get(element) {
if (isPlatformBrowser(this.platformId)) {
return this._svg.get(element);
}
}
}
Angular Universal SPA的元数据标签

SPA 只有一个索引文件,当你需要为不同的路由添加不同的标题和元数据标签时它就会碍事。它跟社交媒体嵌入功能也有关系,你在 Facebook 或 Twitter 分享页面后想要生成预览时它也会出点问题。

为了解决这个问题,我们创建了一个服务,让它为每个页面动态添加必要的元数据标记。

服务示例:

import { Injectable } from '@angular/core';
import { Title, Meta } from '@angular/platform-browser';
import * as seoConfig from '../../../assets/config/seo-config.json';
@Injectable()
export class SeoService {
constructor(private titleService: Title, private meta: Meta) {}
setMeta(page: string) {
this.setTitle(seoConfig[page].title);
this.setNameAttribute('description', seoConfig[page].description);
this.setNameAttribute('keywords', seoConfig[page].keywords);
this.setNameAttribute('twitter:title', seoConfig[page].title);
this.setNameAttribute('twitter:description', seoConfig[page].description);
this.setNameAttribute('twitter:image', seoConfig[page].image);
this.setPropertyAttribute('og:title', seoConfig[page].title);
this.setPropertyAttribute('og:description', seoConfig[page].description);
this.setPropertyAttribute('og:url', seoConfig[page].url);
this.setPropertyAttribute('og:image', seoConfig[page].image);
}
private setTitle(title: string) {
return this.titleService.setTitle(title);
}
private setNameAttribute(attribute: string, value: string) {
if (this.checkAttributeExist(attribute, 'name')) {
this.meta.updateTag({name: attribute, content: value});
} else {
this.meta.addTag({name: attribute, content: value});
}
}
private setPropertyAttribute(attribute: string, value: string) {
if (this.checkAttributeExist(attribute, 'property')) {
this.meta.updateTag({property: attribute, content: value});
} else {
this.meta.addTag({property: attribute, content: value});
}
}
private checkAttributeExist(attribute: string, type: string) {
return this.meta.getTag(`${type}="${attribute}"`);
}

}

然后这个组件会变成:

import { SeoService } from '../core/services/seo.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {
constructor(private seoService: SeoService) {
this.seoService.setMeta('home');
}

使用 seoconfig.json 文件时的情况:

    {
"home": {
"title": "2muchcoffee | Web and Mobile Application Development Company",
"description": "2muchcoffee is top full-stack web and mobile app development company specializing in frontend and backend JS frameworks. Building cross-platform web, hybrid and native mobile applications for established businesses and MVP's for startups.",
"keywords": "2muchcoffee, Angular, frontend, backend",
"url": "https://2muchcoffee.com",
"image": "/assets/img/content/opengraph/main.png"
}
}
第三方库的自定义 Angular 指令

开发者经常会使用基于 Angular 功能的第三方服务,如自定义指令和组件等。这里用 Angular Flex layout 来举例。

它可能会导致一些影响用户体验的意外问题。在服务器端渲染之后,客户端收到的文档已经包含了带有样式的 style 标签。但是 @angular/flex-layout 只在 Angular 库完全加载后才开始工作。

Angular 库加载完毕后才能正确操作上述指令。根据网络情况,从下载初始文档到 Angular 接管之间可能需要几秒钟的延迟。

在此期间,用户可能会看到不包含 flex 标记的页面。等 Angular 启动后所有内容都会归位,但这时页面就会闪烁。

为了解决这个用户体验问题,我们决定拒绝在主页上使用 @angular/flex-layout 指令,并在 CSS 文件中指定 flex 标记属性。

总结
服务器端渲染的优势可能会越来越明显。使用服务器端渲染技术可以方便地开发对 SEO 友好且易于浏览的移动平台 Angular 单页应用,很适合用 Angular 开发电商网站: https://2muchcoffee.com/blog/ecommerce-sites-built-with-angular-made-their-way-to-production

所以现在使用 Angular Universal 和 universal-starter 创建的各种应用就能更容易被搜索到了。

英文原文: https://2muchcoffee.com/blog/angular-universal-seo-spa/

登录查看更多
0

相关内容

搜索引擎优化(Search Engine Optimization,简称SEO)是一种利用搜索引擎的搜索规则来提高
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
117+阅读 · 2020年5月10日
【2020新书】如何认真写好的代码和软件,318页pdf
专知会员服务
63+阅读 · 2020年3月26日
【干货书】流畅Python,766页pdf,中英文版
专知会员服务
224+阅读 · 2020年3月22日
Reformer:一个高效的 Transformer
TensorFlow
9+阅读 · 2020年2月13日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
R_leaflet包_最易上手地图教程(一)
R语言中文社区
10+阅读 · 2019年3月6日
I2P - 适用于黑客的Android应用程序
黑白之道
30+阅读 · 2019年3月6日
可能是 Android 上最好用的写作 App
少数派
10+阅读 · 2018年12月21日
免费云真机测试 | 让您的应用完美适配 Android Oreo
引力空间站
3+阅读 · 2018年2月2日
“我今年36岁了,除了收费啥也不会!”
创业邦杂志
4+阅读 · 2018年1月14日
码农日常工具推荐
架构文摘
4+阅读 · 2017年9月26日
Vue.js 很好,但是比 Angular 或 React 更好吗?
程序猿
3+阅读 · 2017年8月27日
Deformable Style Transfer
Arxiv
14+阅读 · 2020年3月24日
Arxiv
4+阅读 · 2018年11月6日
Arxiv
6+阅读 · 2018年4月4日
Arxiv
3+阅读 · 2018年3月21日
Arxiv
4+阅读 · 2018年2月13日
VIP会员
相关资讯
Reformer:一个高效的 Transformer
TensorFlow
9+阅读 · 2020年2月13日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
R_leaflet包_最易上手地图教程(一)
R语言中文社区
10+阅读 · 2019年3月6日
I2P - 适用于黑客的Android应用程序
黑白之道
30+阅读 · 2019年3月6日
可能是 Android 上最好用的写作 App
少数派
10+阅读 · 2018年12月21日
免费云真机测试 | 让您的应用完美适配 Android Oreo
引力空间站
3+阅读 · 2018年2月2日
“我今年36岁了,除了收费啥也不会!”
创业邦杂志
4+阅读 · 2018年1月14日
码农日常工具推荐
架构文摘
4+阅读 · 2017年9月26日
Vue.js 很好,但是比 Angular 或 React 更好吗?
程序猿
3+阅读 · 2017年8月27日
Top
微信扫码咨询专知VIP会员