Angular のサーバーサイド レンダリング (SSR) について説明する記事

青灯夜游
リリース: 2022-12-27 19:24:07
転載
2073 人が閲覧しました

Angular のサーバーサイド レンダリング (SSR) について説明する記事

一般的に、通常の Angular アプリケーションは ブラウザ で実行され、DOM でページをレンダリングし、ユーザーと対話します。 Angular Universal は、サーバーサイド (サーバーサイド レンダリング、SSR) でレンダリングし、静的なアプリケーション Web ページを生成し、クライアントに表示します。利点は、レンダリングが高速で、完全なレンダリングが可能であることです。インタラクションの前にコンテンツ表示をユーザーに提供できます。 [関連チュートリアルの推奨事項: "angular チュートリアル"]

この記事は Angular 14 環境で完成しています。一部の内容は新しい Angular バージョンに適用できない場合があります。参照してください。 Angularの公式ドキュメント。

SSR を使用する利点

SEO にさらに優しい

Google を含む一部の Web サイトでは現在、検索エンジンとソーシャル メディアは、JavaScript (JS) による SPA (シングル ページ アプリケーション) アプリケーションのクロールをすでにサポートしていると主張していますが、その結果は満足できるものではないようです。静的 HTML Web サイトの SEO パフォーマンスは動的 Web サイトよりも優れており、これは Angular の公式 Web サイトでも同様の見解です (Angular は Google が所有しています!)。

Universal は、JS を使用せずにアプリケーションの静的バージョンを生成でき、検索、外部リンク、ナビゲーションのサポートが強化されています。

モバイル パフォーマンスの向上

一部のモバイル デバイスでは、JS をサポートしていないか、JS のサポートが非常に限られているため、Web サイトへのアクセス エクスペリエンスが非常に低下します。この場合、ユーザーにより良いエクスペリエンスを提供するために、アプリの JS フリー バージョンを提供する必要があります。

ホームページの表示速度の向上

ユーザー エクスペリエンスにとって、ホームページの表示速度は非常に重要です。 eBay によると、検索結果が 100 ミリ秒表示されるごとに、「カートに追加」の使用量が 0.5% 増加します。

ユニバーサルを使用すると、アプリケーションのホームページが完全な形式でユーザーに表示されます。これは純粋な HTML Web ページであり、JS がサポートされていない場合でも表示できます。現時点では、Web ページはブラウザ イベントを処理できませんが、

routerLink を介したジャンプはサポートしています。

この利点は、静的な Web ページを使用して最初にユーザーの注意を引き、ユーザーが Web ページを閲覧するときに同時に Angular アプリケーション全体をロードできることです。これにより、ユーザーは非常に優れた非常に高速な読み込みエクスペリエンスを得ることができます。

SSR をプロジェクトに追加する

Angular CLI を使用すると、通常の Angular プロジェクトを SSR を含むプロジェクトに簡単に変換できます。サーバー側アプリケーションの作成に必要なコマンドは 1 つだけです:

ng add @nguniversal/express-engine
ログイン後にコピー
このコマンドを実行する前に、すべての変更をコミットすることをお勧めします。

このコマンドは、プロジェクトに次の変更を加えます:

  • サーバー ファイルを追加します:

    • main .server .ts - サーバーのメイン プログラム ファイル
    • app/app.server.module.ts - サーバー アプリケーションのメイン モジュール
    • tsconfig.server .json - TypeScript サーバー構成ファイル
    • server.ts - Express Web サーバー実行ファイル
  • 変更されたファイル:

    • package.json - SSR に必要な依存関係を追加し、スクリプトを実行します
    • angular.json - SSR アプリケーションの開発とビルドに必要な構成を追加します。

package.json に、いくつかの npm スクリプトが自動的に追加されます: dev:ssr は、開発環境で SSR バージョンを実行するために使用されます。 serve:ssr は、ビルドまたは事前レンダリングされた Web ページを直接実行するために使用されます。 build:ssr は、 Web ページの SSR バージョン; prerender 事前レンダリングされた Web ページを構築します。build とは異なり、これらのページの HTML ファイルは、提供された routes## に基づいて生成されます。 #。

ブラウザ API の置き換え

ユニバーサル アプリはブラウザでは実行されないため、一部のブラウザ API や機能が利用できなくなります。たとえば、サーバー側アプリケーションは、ブラウザ内のグローバル オブジェクト

window

documentnavigatorlocation を使用できません。 Angular は、サーバー側で同等のオブジェクトを置き換えるために、

Location

DOCUMENT という 2 つの注入可能なオブジェクトを提供します。 たとえば、ブラウザでは、

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 下面只有 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 或者使用命令行参数则按照上面<1><2>中的命令执行),编译完成后,再打开 dist/<your project>/browser 下的 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 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:cnblogs.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!