詳細ガイド
パフォーマンス

サーバーサイドレンダリング

サーバーサイドレンダリング (SSR) は、サーバーでページをレンダリングするプロセスです。これにより、初期のページ状態を含む初期HTMLコンテンツが生成されます。HTMLコンテンツがブラウザに配信されると、Angularはアプリケーションを初期化し、HTMLに含まれるデータを利用します。

SSR を使用する理由

SSRはクライアントサイドレンダリング (CSR) に比べて、主に以下の利点があります。

  • パフォーマンスの向上: SSRは、完全にレンダリングされたHTMLをクライアントに配信することで、Webアプリケーションのパフォーマンスを向上させることができます。これにより、ブラウザはアプリケーションのJavaScriptをダウンロードする前に、HTMLを解析して表示できます。これは、帯域幅の狭い接続やモバイルデバイスのユーザーにとって特に有利です。
  • Core Web Vitals の向上: SSRは、Core Web Vitals (CWV) 統計を使用して測定できるパフォーマンスの向上をもたらします。これには、最初のコンテンツフルペイント (FCP) や最大のコンテンツフルペイント (LCP)、累積レイアウトシフト (CLS) などの指標の改善が含まれます。
  • SEO の向上: SSRは、検索エンジンがアプリケーションのコンテンツをクロールしてインデックス付けしやすくすることで、Webアプリケーションの検索エンジン最適化 (SEO) を向上させることができます。

サーバーサイドレンダリングを有効にする

SSRを使用して新規プロジェクトを作成するには、次のコマンドを実行します。

      
ng new --ssr

既存のプロジェクトにSSRを追加するには、Angular CLIの ng add コマンドを使用します。

      
ng add @angular/ssr

これらのコマンドは、SSRを有効にするためのアプリケーションコードを作成および更新し、プロジェクト構造に余分なファイルを追加します。

      
my-app|-- server.ts                       # アプリケーションサーバー└── src    |-- app    |   └── app.config.server.ts    # サーバーアプリケーション構成    └── main.server.ts              # メインサーバーアプリケーションのブートストラップ

アプリケーションがサーバーサイドでレンダリングされていることを確認するには、ng serve でローカルに実行します。最初のHTMLリクエストには、アプリケーションのコンテンツが含まれている必要があります。

サーバーサイドレンダリングの構成

Note: In Angular v17 and later, server.ts is no longer used by ng serve. The dev server will use main.server.ts directly to perfom server side rendering.

server.ts ファイルは、Node.js ExpressサーバーとAngularサーバーサイドレンダリングを構成します。CommonEngine はAngularアプリケーションをレンダリングするために使用されます。

      
import {APP_BASE_HREF} from '@angular/common';import {CommonEngine} from '@angular/ssr';import express from 'express';import {fileURLToPath} from 'node:url';import {dirname, join, resolve} from 'node:path';import bootstrap from './src/main.server';// The Express app is exported so that it can be used by serverless Functions.export function app(): express.Express {  const server = express();  const serverDistFolder = dirname(fileURLToPath(import.meta.url));  const browserDistFolder = resolve(serverDistFolder, '../browser');  const indexHtml = join(serverDistFolder, 'index.server.html');  const commonEngine = new CommonEngine();  server.set('view engine', 'html');  server.set('views', browserDistFolder);  // TODO: implement data requests securely  // Serve data from URLS that begin "/api/"  server.get('/api/**', (req, res) => {    res.status(404).send('data requests are not yet supported');  });  // Serve static files from /browser  server.get(    '*.*',    express.static(browserDistFolder, {      maxAge: '1y',    }),  );  // All regular routes use the Angular engine  server.get('*', (req, res, next) => {    const {protocol, originalUrl, baseUrl, headers} = req;    commonEngine      .render({        bootstrap,        documentFilePath: indexHtml,        url: `${protocol}://${headers.host}${originalUrl}`,        publicPath: browserDistFolder,        providers: [{provide: APP_BASE_HREF, useValue: req.baseUrl}],      })      .then((html) => res.send(html))      .catch((err) => next(err));  });  return server;}function run(): void {  const port = process.env['PORT'] || 4000;  // Start up the Node server  const server = app();  server.listen(port, () => {    console.log(`Node Express server listening on http://localhost:${port}`);  });}run();

CommonEnginerender メソッドは、以下のプロパティを持つオブジェクトを受け取ります。

プロパティ 詳細 デフォルト値
bootstrap NgModule を返すメソッド、または ApplicationRef に解決されるPromise。
providers 現在のリクエストに対するプラットフォームレベルのプロバイダーの配列。
url レンダリングするページの URL。
inlineCriticalCss レンダリングブロッキングリクエストを減らすために、重要な CSS をインライン化するかどうかのフラグ。 true
publicPath ブラウザファイルとアセットのベースパス。
document サーバーアプリケーションのブートストラップに使用する最初の DOM。
documentFilePath サーバーアプリケーションのブートストラップに使用する最初の DOM のファイルパス。

Angular CLIは、Angularアプリケーションのサーバーサイドレンダリングに焦点を当てた、初期のサーバー実装をスキャフォールディングします。このサーバーは、APIルート、リダイレクト、静的アセットなど、他の機能をサポートするように拡張できます。詳細については、Express ドキュメント を参照してください。

ハイドレーション

ハイドレーションは、クライアント上でサーバーサイドレンダリングされたアプリケーションを復元するプロセスです。これには、サーバーでレンダリングされたDOM構造の再利用、アプリケーション状態の永続化、サーバーが既に取得したアプリケーションデータの転送、その他のプロセスが含まれます。ハイドレーションは、SSRを使用する場合、デフォルトで有効になります。ハイドレーションの詳細については、ハイドレーションガイド を参照してください。

HttpClient を使用する場合のデータキャッシュ

HttpClient は、サーバーで実行されているときに、送信されるネットワークリクエストをキャッシュします。この情報はシリアル化され、サーバーから送信される最初のHTMLの一部としてブラウザに転送されます。ブラウザでは、HttpClient はキャッシュにデータが存在するかどうかをチェックし、存在する場合は初期アプリケーションレンダリング中に新しいHTTPリクエストを行う代わりに、キャッシュされたデータを使用します。HttpClient は、ブラウザで実行されているアプリケーションが安定すると、キャッシュの使用を停止します。

デフォルトでは、HttpClient は、Authorization または Proxy-Authorization ヘッダーが含まれていないすべての HEAD および GET リクエストをキャッシュします。これらの設定は、ハイドレーションを提供するときに withHttpTransferCacheOptions を使用することでオーバーライドできます。

      
bootstrapApplication(AppComponent, {  providers: [    provideClientHydration(withHttpTransferCacheOptions({      includePostRequests: true    }))  ]});

サーバー対応コンポーネントのオーサリング

一部の一般的なブラウザAPIや機能は、サーバーでは使用できない場合があります。アプリケーションは、windowdocumentnavigatorlocation などのブラウザ固有のグローバルオブジェクト、および HTMLElement の特定のプロパティを使用できません。

一般的に、ブラウザ固有のシンボルに依存するコードは、サーバーではなく、ブラウザでのみ実行する必要があります。これは、afterRender および afterNextRender ライフサイクルフックを使用して強制できます。これらは、ブラウザでのみ実行され、サーバーではスキップされます。

      
import { Component, ViewChild, afterNextRender } from '@angular/core';@Component({  selector: 'my-cmp',  template: `<span #content>{{ ... }}</span>`,})export class MyComponent {  @ViewChild('content') contentRef: ElementRef;  constructor() {    afterNextRender(() => {      // `scrollHeight` をチェックしても安全です。これはブラウザでのみ実行され、サーバーでは実行されないためです。      console.log('content height: ' + this.contentRef.nativeElement.scrollHeight);    });  }}

Angular Service Worker の使用

サーバーでAngularをAngular Service Workerと組み合わせて使用している場合、動作は通常のサーバーサイドレンダリングの動作とは異なります。最初のサーバーリクエストは、期待どおりにサーバーでレンダリングされます。ただし、その最初のリクエストの後、後続のリクエストはService Workerによって処理され、常にクライアントサイドでレンダリングされます。