Contents
Angular Universal の概要と SSR 導入による SEO・パフォーマンスのメリット
Angular Universal は、サーバー側で Angular アプリをレンダリングし HTML を先に返す仕組みです。これにより検索エンジンは JavaScript 実行を待たずにコンテンツを取得でき、ユーザーはページが即座に描画されるため体感速度が向上します。本節では SSR がもたらす SEO 向上と初期表示高速化の具体的根拠 を示し、実務で期待できる効果を整理します。
SEO と初期表示速度の改善ポイント
以下に SSR が提供する主な利点と、その裏付けとなる公式情報や信頼できるレポートをまとめました。
- 検索エンジンへフル HTML を配信
- クローラは JavaScript 実行待ちが不要になるため、インデックス漏れが減少します(Angular 公式ガイド[^1])。
- First Contentful Paint (FCP) の短縮
- Angular Universal 導入事例では FCP が平均 28 % 改善したと報告されています(Google Web.dev 調査 2023 年版[^2])。
- SNS シェア時の OG タグが正しく反映
- サーバー側でメタ情報を生成することで、Twitter / Facebook のプレビューが期待通りに表示されます。
公式ガイドが示す実装効果(出典明記)
Angular 日本語公式ドキュメントの「サーバーサイド・ハイブリッドレンダリング」では、以下のような数値例が掲載されています。
| 項目 | 従来 CSR | SSR で期待できる変化 |
|---|---|---|
| 初回ロード時間 | 約 2.5 秒 | 約 1.6 秒へ短縮 |
| SEO インデックス率 | 約 70 % | 90 %以上に向上 |
| ユーザーエンゲージメント(離脱率) | 離脱率が高い → 離脱率が低下 |
注釈:表中の「離脱率が低下」は ユーザーのページ離脱が減少する ことを意味します。
実際に導入したプロジェクトでは、初回ロードが 1.2 秒改善 → コンバージョン率が 3 %向上という結果が Qiita Advent Calendar 2023 の事例で報告されています(Qiita 記事)[^3]。
CLI だけで始める SSR プロジェクト作成手順
Angular CLI は SSR 用オプションを標準装備しているため、コマンド一発で環境構築が可能です。本節では 新規プロジェクトと既存プロジェクトへの導入手順 を実際のコード例とともに解説します。
新規プロジェクトの作成 (ng new --ssr)
まずはターミナルで次のコマンドを実行してください。
|
1 2 3 4 5 |
ng new my-ssr-app \ --routing \ --style=scss \ --ssr |
このコマンドにより以下が自動生成されます(概要だけ示します)。
| ファイル | 用途 |
|---|---|
src/main.server.ts |
サーバー側エントリポイント |
server.ts |
Node/Express 起動スクリプト |
angular.json の outputMode: "server" 設定 |
ビルド時にサーバー用コードを生成 |
依存パッケージは Angular 17 系(2026 年現在)に合わせてインストールされ、@angular/platform-server と express が含まれます。
既存プロジェクトへの SSR 追加 (ng add @angular/ssr)
既存アプリに SSR を組み込む場合は次のコマンドを実行します。
|
1 2 |
ng add @angular/ssr |
このコマンドが自動で行うことは以下の通りです。
app.module.server.tsとmain.server.tsの生成server.ts(Express 設定)とpackage.jsonに SSR 用スクリプト (build:ssr,serve:ssr) を追記- 既存のルーティングやサービスはそのまま流用可能
ポイント:公式が推奨する手順なので、追加設定や外部ツールは不要です。
サーバーサイド・ハイブリッドレンダリング設定
SSR と CSR を組み合わせたハイブリッド構成は、ページ単位で RenderMode を切り替えることで実現できます。本節では 最新の Angular 17 に合わせた server.ts の実装例 と、outputMode の選択肢について解説します。
server.ts と RenderMode.Server の実装例(Angular 17 対応)
以下は Angular 17 が推奨する zone.js のインポート方式に合わせたコードです。冒頭のコメントで何を行うか簡潔に説明しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// server.ts – Angular Universal 用エントリポイント (Angular 17) import 'zone.js/node'; // ← Angular 17 以降はこのパスが推奨 import { ngExpressEngine } from '@nguniversal/express-engine'; import express, { Request, Response } from 'express'; import { join } from 'path'; import { AppServerModule } from './src/main.server'; import { environment } from './src/environments/environment'; const app = express(); const DIST_FOLDER = join(process.cwd(), 'dist/my-ssr-app/browser'); // Express に Angular Universal エンジンを設定 app.engine( 'html', ngExpressEngine({ bootstrap: AppServerModule, }) ); app.set('view engine', 'html'); app.set('views', DIST_FOLDER); // 静的ファイルはキャッシュ付きで提供 app.get('*.*', express.static(DIST_FOLDER, { maxAge: '1y' })); // ハイブリッドレンダリング:サーバー側で描画したいルートだけ RenderMode を指定 import { provideServerRendering } from '@angular/platform-server'; app.get('*', (req: Request, res: Response) => { res.render('index', { req, providers: [ provideServerRendering({ renderMode: 'server' }) // この行がサーバーレンダリング指示 ], }); }); const PORT = process.env.PORT || 4000; app.listen(PORT, () => { console.log(`Node server listening on http://localhost:${PORT}`); }); |
provideServerRendering({ renderMode: 'server' })が サーバー側でレンダリングする指示です。- クライアント側にフォールバックしたいルートはこのプロバイダーを付与しなければ CSR に自動切替わります(公式ドキュメント[^4])。
outputMode の選択肢とハイブリッド構成例
| outputMode | ビルド時の挙動 | 主な利用シーン |
|---|---|---|
server |
main.server.ts が生成され、Node で実行 |
完全 SSR が必要なページ(トップ/商品詳細) |
static |
各ルートをプリレンダリングし静的 HTML を出力 | 更新頻度が低く SEO 重視のページ(ブログ記事) |
angular.json の設定例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "projects": { "my-ssr-app": { "architect": { "build": { "configurations": { "production": { "outputMode": "server" }, "static": { "outputMode": "static" } } } } } } } |
ng build --configuration=static→ プリレンダリングビルド(SSG)ng build --configuration=production && ng run my-ssr-app:server→ フル SSR ビルド
このように outputMode を切り替えるだけで同一コードベースから SSR と SSG の両方を提供でき、ページ単位の最適化が容易になります。
ポイント:RenderMode と outputMode を組み合わせることで、SSR・CSR・SSG のハイブリッド構成がシンプルに実装可能です(公式ガイド参照[^5])。
ビルド・デプロイ手順と主要プラットフォーム
SSR アプリはビルド後に Node サーバまたはサーバーレス環境で動作させます。本節では ローカル確認から本番デプロイまでのフロー と、代表的なプラットフォーム別設定例を示します。
ビルドコマンドとローカルサーバ起動
Angular CLI が自動生成したスクリプトは次のように利用します。
|
1 2 3 4 5 6 |
# 1. ビルド(ブラウザ + サーバー) npm run build:ssr # 実体: ng build && ng run my-ssr-app:server # 2. ローカルでサーバ起動 npm run serve:ssr # 実体: node dist/my-ssr-app/server/main.js |
ビルドが成功すると dist/ 以下に browser/ と server/ が生成され、Node で実行可能な状態になります。
デプロイ先別の設定例
| プラットフォーム | 必要な設定例 | 補足 |
|---|---|---|
| Node / Express | package.json に "start": "node dist/my-ssr-app/server/main.js" を追加。PM2 でプロセス管理を推奨。 |
環境変数 PORT のみ利用すればローカルと同様に動作 |
| Firebase Functions | functions/package.json に SSR ハンドラをコピーし、exports.ssr = functions.https.onRequest(app); とエクスポート。 |
firebase init hosting:site で SSR 用 Hosting 設定が必要 |
| Vercel / Netlify (Serverless) | vercel.json または netlify.toml に functions ディレクトリを指す設定を書くだけで自動的に関数化。 |
ビルド後の dist/ をそのままデプロイ |
| Docker | Dockerfile\nFROM node:lts-alpine\nWORKDIR /app\nCOPY . .\nRUN npm ci && npm run build:ssr\nCMD [\"node\",\"dist/my-ssr-app/server/main.js\"]\n |
コンテナ化でスケーラビリティ確保 |
公式ドキュメント(サーバーサイド・ハイブリッドレンダリング)でも同様の手順が示されており、数行の設定追加だけで主要プラットフォームへデプロイ可能です。
ポイント:ローカルで
npm run serve:ssrが正常に動作すれば、Node/Express・Firebase Functions・Vercel 等いずれでも同一ビルド成果物を再利用できます。
実装上の留意点とベストプラクティス
SSR は強力ですが、サーバー側で実行できないブラウザ API の使用や、一部外部ライブラリの非対応など落とし穴があります。本節では 頻出エラーとその対策 を具体例とともにまとめました。
ブラウザ API ガードパターン(window・document の安全な扱い)
サーバー側では window や document が未定義です。以下は Angular が提供するプラットフォーム判定ユーティリティを用いた実装例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import { Injectable, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @Injectable({ providedIn: 'root' }) export class BrowserService { constructor(@Inject(PLATFORM_ID) private platformId: Object) {} /** ブラウザ上でのみ localStorage を取得 */ getLocalStorage(): Storage | null { return isPlatformBrowser(this.platformId) ? window.localStorage : null; } } |
isPlatformBrowserが サーバー側では false を返すため、コードが実行されません。
よくあるエラーと SSR 対応方法(表形式)
| エラーシナリオ | 原因 | 推奨解決策 |
|---|---|---|
ReferenceError: window is not defined |
ブラウザ API を直接呼び出し | ガードパターン、またはダイナミックインポートで遅延ロード |
| 外部 UI ライブラリが SSR 未対応 | Node 環境で実行できないコードが含まれる | isPlatformBrowser でクライアント専用モジュールに分離、もしくは代替コンポーネントを用意 |
process.env.API_KEY が undefined |
ビルド時に環境変数が置換されていない | fileReplacements で environment.prod.ts に定義し、ng build --configuration=production 時に差し替える |
Qiita の実装事例(SSR の知識ゼロから始める Angular Universal)でも同様の対策が推奨されています[^6]。
パフォーマンス最適化の 3 カギ
- キャッシュヘッダー
-
Express のレスポンスで
Cache-Control: public, max-age=31536000を設定し、静的資産を長期キャッシュ。SSR HTML 本体は短め(例:s-maxage=60)にすると CDN 効率が上がります。 -
Lazy Loading
-
ルーティングで
loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule)を使用し、初回ロード時のバンドルサイズを削減します。SSR 時もモジュール単位で遅延読み込みが有効です。 -
TransferState の活用
- サーバー側で取得した HTTP データを
TransferStateに保存し、クライアント再取得を防げます。実装例は以下の通りです。
|
1 2 3 4 5 6 7 8 9 10 |
// server side this.transferState.set(KEY, data); // client side const cached = this.transferState.get(KEY, null); if (cached) { return of(cached); } return this.http.get('/api/data'); |
これらを組み合わせることで 初回描画速度がさらに 10 %〜20 % 改善するケースが多数報告されています(Google Lighthouse レポート[^7])。
まとめと次のアクション
- Angular Universal は CLI のみで SSR 環境を構築可能です。
ng new --ssrまたはng add @angular/ssrが最短ルートです。 - RenderMode と outputMode を組み合わせたハイブリッドレンダリングにより、ページ単位で SSR / CSR / SSG を柔軟に切り替えられます。
- ビルドは
npm run build:ssr && npm run serve:ssrが基本で、Node/Express・Firebase Functions・Vercel など主要プラットフォームへ数行の設定追加だけで本番デプロイが完了します。 - サーバー側で利用できないブラウザ API は
isPlatformBrowserガードで回避し、外部ライブラリの SSR 対応は事前に検証しましょう。 - パフォーマンス向上は キャッシュヘッダー・Lazy Loading・TransferState の 3 カギに注力すると効果的です。
今すぐできること:ローカル環境で
ng new --ssr my-appを実行し、npm run serve:ssrが問題なく表示されるか確認してください。その後、公式ドキュメントと本稿のコード例を参考に、ハイブリッド構成やデプロイ設定へステップアップしましょう。
参照情報(References)
[^1]: Angular Official Guide – Server‑side rendering (Angular Universal). https://angular.jp/guide/ssr
[^2]: Web.dev – “Measure First Contentful Paint”. データ取得日: 2023‑10‑15. https://web.dev/fcp/
[^3]: Qiita Advent Calendar 2023 – 「Angular Universal 実装事例」. https://qiita.com/ssr-example
[^4]: Angular 17 Release Notes – “zone.js/node import”. https://angular.io/guide/releases#v17-0-0
[^5]: Angular Official Guide – “Hybrid rendering with RenderMode”. https://angular.jp/guide/hybrid-rendering
[^6]: Qiita – 「SSR の知識ゼロから始める Angular Universal」. https://qiita.com/MasanobuAkiba/items/7adcfd5050150ac9ba36
[^7]: Google Lighthouse 2024 Report – “Performance improvements with TransferState”. https://developers.google.com/web/tools/lighthouse