LoginSignup
5
1

AngularではじめるSSR入門

Last updated at Posted at 2023-12-14

これはAngular Advent Calendar 2023の15日目の記事です。

はじめに

サーバーサイドレンダリング(SSR)って、なんか難しそうなイメージありますよね?
その割にメリットが少ないので、Angular Universalの存在は知っていたけど使ったことはない、という人は多いと思います。(自分もそうでした。)

そんな食わず嫌いの方々に向けて、本記事ではAngular SSRの環境構築からデプロイまでをさくっと紹介します。

前提条件

本記事の環境構築はこちらのバージョンで確認しています。

$ ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 17.0.3
Node: 18.17.1
Package Manager: npm 9.8.1
OS: darwin arm64

Angular: 
... 

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1700.3 (cli-only)
@angular-devkit/core         17.0.3 (cli-only)
@angular-devkit/schematics   17.0.3 (cli-only)
@schematics/angular          17.0.3 (cli-only)

環境構築

新たにAngular SSRプロジェクトを作成します。プロジェクト名はng17-ssrとします。

$ ng new --ssr
? What name would you like to use for the new workspace and initial project? ng17-ssr

パッケージのインストールが終わったら、早速開発サーバーを起動してみます。

$ npm run start

ブラウザを開いてhttp://localhost:4200にアクセスしてみると、新しくなったHelloページが表示されました。

image.png

そして、なんとこのページはSSRされています!

ブラウザのJavaScriptを無効化しても同じように表示されるはずです。

プリレンダリング(SSG)

プリレンダリングも簡単に確認できるので、やってみます。

実際は、この段階でも有効化されているのですが、わかりずらいので少し手を加えます。
具体的には、ランダムなUUIDを返してくれるAPIを使います。

まず、app.config.tsHttpClientを使うための設定を追加します。

app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { provideHttpClient } from '@angular/common/http';
import { provideClientHydration } from '@angular/platform-browser';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideClientHydration(),
+   provideHttpClient(),
  ],
};

次に、app.component.tsでUUIDをAPIから取得して、表示させます。

app.component.ts
  import { CommonModule } from '@angular/common';
+ import { HttpClient } from '@angular/common/http';
+ import { Component, inject } from '@angular/core';
  import { RouterOutlet } from '@angular/router';

  @Component({
    selector: 'app-root',
    standalone: true,
    imports: [CommonModule, RouterOutlet],
    templateUrl: './app.component.html',
    styleUrl: './app.component.css',
  })
  export class AppComponent {
-  title = 'ng17-ssr'
+  private readonly http = inject(HttpClient);
+  uuid = '';
+  
+  ngOnInit(): void {
+    this.http
+      .get('https://www.uuidtools.com/api/generate/v4/count/1')
+      .subscribe((uuid: any) => {
+        this.uuid = uuid;
+      });
+    }
  }
app.component.html
+ UUID: {{ uuid }}

次に、ビルドします。

$ npm run build

dist/ng17-ssr/browser/index.htmlにビルドされた結果が格納されます。

index.html
// ...
<app-root _nghost-ng-c1557180121 ng-version="17.0.6" ngh="0" ng-server-context="ssg">UUID: 3a67fab7-ec86-418b-8b05-96f561a17457
</app-root>

API経由で取得したUUIDが埋め込まれていることが確認できました。

特定のパスだけプリレンダリングする

デフォルトでは全てのパスをプリレンダリングしますが、特定のパスのみを対象にすることもできます。
その場合、まずangular.jsonの設定を変更します。

angular.json
  {
-   "prerender": true
+   "prerender": {
+     "discoverRoutes": false,
+     "routesFile": "prerender-routes.txt"
+   }
  }

さらに、ルート直下にprerender-routes.txtを作成します。
例えば、/foo/barがあって、/barのみをSSGしたい場合は次のように記述します。

prerender-routes.txt
/bar

この状態でビルドすると、dist/ng17-ssr/browser/bar/index.htmlは生成されますが、dist/ng17-ssr/browser/foo/index.htmlは生成されないことが確認できます。

デプロイする

Vercelへデプロイして動作確認してみます。
個人利用の範囲(Hobby Plan)であれば、無料で使用できます。

まず、Vercel用の設定を追加します。
ルート直下にapi/index.mjsvercel.jsonを追加します。
ng17-ssrの部分は各々のプロジェクト名に読み替えてください。

index.mjs
import { app } from "../dist/ng17-ssr/server/server.mjs";

export default app();
vercel.json
{
  "rewrites": [{ "source": "/(.*)", "destination": "/api" }],
  "functions": {
    "api/index.mjs": {
      "includeFiles": "dist/ng17-ssr/server/**"
    }
  }
}

GitHubにPushして、Vercelからリポジトリを選択、デプロイします。
デプロイ設定はFramework PresetにAngularを選択するだけでOKです。

image.png

無事にデプロイされたら動作確認してみましょう。

ng17-ssr.gif

/fooはプリレンダリングされていないので、リロードするたびに表示されるUUIDが変更されますが、/barはプリレンダリングされているため、リロードしても同じUUIDが表示されます。

まとめ

やってみると案外簡単でした。SSR/SSGのフレームワークとしてAngularを使うケースが、今後増えてくるといいですね。

既存のアプリケーションに対しても、SSRはサーバーが必要なので少しハードルが高いですが、プリレンダリングだけであれば、すぐにでも導入できるので、試してみてはいかがでしょうか。

明日は、@komura_cさんです。

参考

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1