搜尋
首頁web前端js教程一文探究Angular中的服務端渲染(SSR)

一文探究Angular中的服務端渲染(SSR)

一般來說,普通的 Angular 應用程式是在 瀏覽器 中運行,在 DOM 中對頁面進行渲染,並與使用者互動。而Angular Universal 是在服務端 進行渲染(Server-Side Rendering,SSR),產生靜態的應用程式網頁,然後在客戶端展示,好處是可以更快地進行渲染,在提供完整的互動之前就可以提供使用者內容展示。 【相關教學推薦:《angular教學》】

本文是在Angular 14 環境中完成,有些內容對於新的Angular 版本可能並不適用,請參考Angular 官方文件.

使用SSR 的好處

對SEO 更友善

雖然現在包括Google 在內的某些搜尋引擎和社群媒體聲稱已經能支援對由JavaScript(JS)驅動的SPA(Single-Page Application)應用程式進行爬取,但是結果似乎差強人意。靜態 HTML 網站的 SEO 表現還是比動態網站,這也是 Angular 官網所持有的觀點(Angular 可是 Google 的!)。

Universal 可以產生無 JS 的靜態版本的應用程序,對搜尋、外鏈、導航的支援更好。

提高行動端的效能

某些行動裝置可能不支援 JS 或對 JS 的支援非常有限,導致網站的存取體驗非常差。在這種情況下,我們需要提供無 JS 版本的應用,以便為使用者提供更好的體驗。

更快地展示首頁

對於使用者的使用體驗來說,首頁展示速度的快慢至關重要。根據 eBay 的數據,搜尋結果的展示速度每提高 100 毫秒,「加入購物車」的使用率就提高 0.5%。

使用了 Universal 之後,應用程式的首頁會以完整的形態展示給用戶,這是純的 HTML 網頁,即使不支援 JS,也可以展示。此時,網頁雖然無法處理瀏覽器的事件,但支援透過 routerLink 進行跳轉。

這麼做的好處是,我們可以先用靜態網頁抓住使用者的注意力,在使用者瀏覽網頁的時候,同時載入整個 Angular 應用程式。這給了用戶一個非常好的極速加載的體驗。

為專案增加 SSR

Angular CLI 可以幫助我們非常方便的將一個普通的 Angular 專案轉變為一個帶有 SSR 的專案。建立服務端應用程式只需要一個指令:

ng add @nguniversal/express-engine

建議在執行該指令之前先提交所有的變更。

這個指令會對專案做如下修改:

  • 新增服務端檔案:

    • main.server .ts - 服務端主程式檔案
    • app/app.server.module.ts - 服務端應用程式主模組
    • tsconfig. server.json - TypeScript 服務端設定檔
    • server.ts - Express web server 的執行檔
  • #已修改的檔案:

    • package.json - 新增SSR 所需的依賴與執行腳本
    • angular.json - 新增開發、建置SSR 應用程式所需的設定

package.json 中,會自動加入一些npm 腳本: dev:ssr 用於在開發環境中執行SSR 版本;serve:ssr 用於直接執行build 或prerender 後的網頁;build:ssr 建置SSR 版本的網頁; prerender 建立預渲染後的網頁,與build 不同,這裡會根據提供的routes 產生這些頁面的HTML 檔案。

取代瀏覽器 API

由於 Universal 應用程式不是在瀏覽器中執行,因此某些瀏覽器的 API 或功能將不可用。例如,服務端應用程式是無法使用瀏覽器中的全域物件 windowdocumentnavigatorlocation

Angular 提供了兩個可注入對象,用於在服務端替換對等的對象:LocationDOCUMENT

例如,在瀏覽器中,我們透過window.location.href 取得目前瀏覽器的位址,而改成SSR 之後,程式碼如下:

import { Location } from '@angular/common';
 
export class AbmNavbarComponent implements OnInit{
  // ctor 中注入 Location
  constructor(private _location:Location){
    //...
  }
 
  ngOnInit() {
    // 打印当前地址
    console.log(this._location.path(true));
  }
}

同樣,對於在瀏覽器使用document.getElementById() 取得DOM 元素,在改成SSR 之後,程式碼如下:

import { DOCUMENT } from '@angular/common';
 
export class AbmFoxComponent implements OnInit{
  // ctor 中注入 DOCUMENT
  constructor(@Inject(DOCUMENT) private _document: Document) { }
 
  ngOnInit() {
    // 获取 id 为 fox-container 的 DOM
    const container = this._document.getElementById('fox-container');
  }
}

使用 URL 绝对地址

在 Angular SSR 应用中,HTTP 请求的 URL 地址必须为 绝对地址(即,以 http/https 开头的地址,不能是相对地址,如 /api/heros)。Angular 官方推荐将请求的 URL 全路径设置到 renderModule()renderModuleFactory()options 参数中。但是在 v14 自动生成的代码中,并没有显式调用这两个方法的代码。而通过读 Http 请求的拦截,也可以达到同样的效果。

下面我们先准备一个拦截器,假设文件位于项目的 shared/universal-relative.interceptor.ts 路径:

import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Inject, Injectable, Optional } from '@angular/core';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { Request } from 'express';
 
// 忽略大小写检查
const startsWithAny = (arr: string[] = []) => (value = '') => {
    return arr.some(test => value.toLowerCase().startsWith(test.toLowerCase()));
};
 
// http, https, 相对协议地址
const isAbsoluteURL = startsWithAny(['http', '//']);
 
@Injectable()
export class UniversalRelativeInterceptor implements HttpInterceptor {
    constructor(@Optional() @Inject(REQUEST) protected request: Request) { }
 
    intercept(req: HttpRequest<any>, next: HttpHandler) {
        // 不是绝对地址的 URL
        if (!isAbsoluteURL(req.url)) {
            let protocolHost: string;
            if (this.request) {
                // 如果注入的 REQUEST 不为空,则从注入的 SSR REQUEST 中获取协议和地址
                protocolHost = `${this.request.protocol}://${this.request.get(
                    &#39;host&#39;
                )}`;
            } else {
                // 如果注入的 REQUEST 为空,比如在进行 prerender build:
                // 这里需要添加自定义的地址前缀,比如我们的请求都是从 abmcode.com 来。
                protocolHost = &#39;https://www.abmcode.com&#39;;
            }
            const pathSeparator = !req.url.startsWith(&#39;/&#39;) ? &#39;/&#39; : &#39;&#39;;
            const url = protocolHost + pathSeparator + req.url;
            const serverRequest = req.clone({ url });
            return next.handle(serverRequest);
 
        } else {
            return next.handle(req);
        }
    }
}

然后在 app.server.module.ts 文件中 provide 出来:

import { UniversalRelativeInterceptor } from &#39;./shared/universal-relative.interceptor&#39;;
// ... 其他 imports

@NgModule({
  imports: [
    AppModule,
    ServerModule,
    // 如果你用了 @angular/flext-layout,这里也需要引入服务端模块
    FlexLayoutServerModule, 
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: UniversalRelativeInterceptor,
      multi: true
    }
  ],
  bootstrap: [AppComponent],
})
export class AppServerModule { }

这样任何对于相对地址的请求都会自动转换为绝对地址请求,在 SSR 的场景下不会再出问题。

Prerender 预渲染静态 HTML

经过上面的步骤后,如果我们通过 npm run build:ssr 构建项目,你会发现在 dist/<your project>/browser</your> 下面只有 index.html 文件,打开文件查看,发现其中还有 <app-root></app-root> 这样的元素,也就是说你的网页内容并没有在 html 中生成。这是因为 Angular 使用了动态路由,比如 /product/:id 这种路由,而页面的渲染结果要经过 JS 的执行才能知道,因此,Angular 使用了 Express 作为 Web 服务器,能在服务端运行时根据用户请求(爬虫请求)使用模板引擎生成静态 HTML 界面。

prerendernpm run prerender)会在构建时生成静态 HTML 文件。比如我们做企业官网,只有几个页面,那么我们可以使用预渲染技术生成这几个页面的静态 HTML 文件,避免在运行时动态生成,从而进一步提升网页的访问速度和用户体验。

预渲染路径配置

需要进行预渲染(预编译 HTML)的网页路径,可以有几种方式进行提供:

  • 通过命令行的附加参数:

    ng run <app-name>:prerender --routes /product/1 /product/2
  • 如果路径比较多,比如针对 product/:id 这种动态路径,则可以使用一个路径文件:

    routes.txt

    /products/1
    /products/23
    /products/145
    /products/555

    然后在命令行参数指定该文件:

    ng run <app-name>:prerender --routes-file routes.txt
  • 在项目的 angular.json 文件配置需要的路径:

     "prerender": {
       "builder": "@nguniversal/builders:prerender",
       "options": {
         "routes": [ // 这里配置
           "/",
           "/main/home",
           "/main/service",
           "/main/team",
           "/main/contact"
         ]
       },

配置完成后,重新执行预渲染命令(npm run prerender 或者使用命令行参数则按照上面中的命令执行),编译完成后,再打开 dist/<your project>/browser</your> 下的 index.html 会发现里面没有 <app-root></app-root> 了,取而代之的是主页的实际内容。同时也生成了相应的路径目录以及各个目录下的 index.html 子页面文件。

SEO 优化

SEO 的关键在于对网页 titlekeywordsdescription 的收录,因此对于我们想要让搜索引擎收录的网页,可以修改代码提供这些内容。

在 Angular 14 中,如果路由界面通过 Routes 配置,可以将网页的静态 title 直接写在路由的配置中:

{ path: &#39;home&#39;, component: AbmHomeComponent, title: &#39;<你想显示在浏览器 tab 上的标题>&#39; },

另外,Angular 也提供了可注入的 TitleMeta 用于修改网页的标题和 meta 信息:

import { Meta, Title } from &#39;@angular/platform-browser&#39;;
 
export class AbmHomeComponent implements OnInit {
 
  constructor(
    private _title: Title,
    private _meta: Meta,
  ) { }
 
  ngOnInit() {
    this._title.setTitle(&#39;<此页的标题>&#39;);
    this._meta.addTags([
      { name: &#39;keywords&#39;, content: &#39;<此页的 keywords,以英文逗号隔开>&#39; },
      { name: &#39;description&#39;, content: &#39;<此页的描述>&#39; }
    ]);
  }
}

总结

Angular 作为 SPA 企业级开发框架,在模块化、团队合作开发方面有自己独到的优势。在进化到 v14 这个版本中提供了不依赖 NgModule 的独立 Component 功能,进一步简化了模块化的架构。

Angular Universal 主要关注将 Angular App 如何进行服务端渲染和生成静态 HTML,对于用户交互复杂的 SPA 并不推荐使用 SSR。针对页面数量较少、又有 SEO 需求的网站或系统,则可以考虑使用 Universal 和 SSR 技术。

更多编程相关知识,请访问:编程教学!!

以上是一文探究Angular中的服務端渲染(SSR)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:博客园。如有侵權,請聯絡admin@php.cn刪除
聊聊Angular中的元数据(Metadata)和装饰器(Decorator)聊聊Angular中的元数据(Metadata)和装饰器(Decorator)Feb 28, 2022 am 11:10 AM

本篇文章继续Angular的学习,带大家了解一下Angular中的元数据和装饰器,简单了解一下他们的用法,希望对大家有所帮助!

angular学习之详解状态管理器NgRxangular学习之详解状态管理器NgRxMay 25, 2022 am 11:01 AM

本篇文章带大家深入了解一下angular的状态管理器NgRx,介绍一下NgRx的使用方法,希望对大家有所帮助!

一文探究Angular中的服务端渲染(SSR)一文探究Angular中的服务端渲染(SSR)Dec 27, 2022 pm 07:24 PM

你知道 Angular Universal 吗?可以帮助网站提供更好的 SEO 支持哦!

项目过大怎么办?如何合理拆分Angular项目?项目过大怎么办?如何合理拆分Angular项目?Jul 26, 2022 pm 07:18 PM

Angular项目过大,怎么合理拆分它?下面本篇文章给大家介绍一下合理拆分Angular项目的方法,希望对大家有所帮助!

Angular + NG-ZORRO快速开发一个后台系统Angular + NG-ZORRO快速开发一个后台系统Apr 21, 2022 am 10:45 AM

本篇文章给大家分享一个Angular实战,了解一下angualr 结合 ng-zorro 如何快速开发一个后台系统,希望对大家有所帮助!

聊聊Angular Route中怎么提前获取数据聊聊Angular Route中怎么提前获取数据Jul 13, 2022 pm 08:00 PM

Angular Route中怎么提前获取数据?下面本篇文章给大家介绍一下从 Angular Route 中提前获取数据的方法,希望对大家有所帮助!

浅析Angular中的独立组件,看看怎么使用浅析Angular中的独立组件,看看怎么使用Jun 23, 2022 pm 03:49 PM

本篇文章带大家了解一下Angular中的独立组件,看看怎么在Angular中创建一个独立组件,怎么在独立组件中导入已有的模块,希望对大家有所帮助!

Vue 3中的SSR技术应用实践,提升应用的SEO效果Vue 3中的SSR技术应用实践,提升应用的SEO效果Sep 08, 2023 pm 12:15 PM

Vue3中的SSR技术应用实践,提升应用的SEO效果随着前端开发的快速发展,SPA(单页面应用)已经成为了主流。SPA的好处不言而喻,可以提供流畅的用户体验,但却在SEO(搜索引擎优化)方面有一些挑战。由于SPA在前端渲染阶段只返回一个HTML模板,大部分内容是通过JavaScript动态加载的,导致搜索引擎在抓取、索引和排名方面的困难。为了解决这个问题,

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
1 個月前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)