これは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ページが表示されました。
そして、なんとこのページはSSRされています!
ブラウザのJavaScriptを無効化しても同じように表示されるはずです。
プリレンダリング(SSG)
プリレンダリングも簡単に確認できるので、やってみます。
実際は、この段階でも有効化されているのですが、わかりずらいので少し手を加えます。
具体的には、ランダムなUUIDを返してくれるAPIを使います。
まず、app.config.ts
にHttpClient
を使うための設定を追加します。
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から取得して、表示させます。
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;
+ });
+ }
}
+ UUID: {{ uuid }}
次に、ビルドします。
$ npm run build
dist/ng17-ssr/browser/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
の設定を変更します。
{
- "prerender": true
+ "prerender": {
+ "discoverRoutes": false,
+ "routesFile": "prerender-routes.txt"
+ }
}
さらに、ルート直下にprerender-routes.txt
を作成します。
例えば、/foo
と/bar
があって、/bar
のみをSSGしたい場合は次のように記述します。
/bar
この状態でビルドすると、dist/ng17-ssr/browser/bar/index.html
は生成されますが、dist/ng17-ssr/browser/foo/index.html
は生成されないことが確認できます。
デプロイする
Vercelへデプロイして動作確認してみます。
個人利用の範囲(Hobby Plan)であれば、無料で使用できます。
まず、Vercel用の設定を追加します。
ルート直下にapi/index.mjs
とvercel.json
を追加します。
ng17-ssr
の部分は各々のプロジェクト名に読み替えてください。
import { app } from "../dist/ng17-ssr/server/server.mjs";
export default app();
{
"rewrites": [{ "source": "/(.*)", "destination": "/api" }],
"functions": {
"api/index.mjs": {
"includeFiles": "dist/ng17-ssr/server/**"
}
}
}
GitHubにPushして、Vercelからリポジトリを選択、デプロイします。
デプロイ設定はFramework PresetにAngularを選択するだけでOKです。
無事にデプロイされたら動作確認してみましょう。
/foo
はプリレンダリングされていないので、リロードするたびに表示されるUUIDが変更されますが、/bar
はプリレンダリングされているため、リロードしても同じUUIDが表示されます。
まとめ
やってみると案外簡単でした。SSR/SSGのフレームワークとしてAngularを使うケースが、今後増えてくるといいですね。
既存のアプリケーションに対しても、SSRはサーバーが必要なので少しハードルが高いですが、プリレンダリングだけであれば、すぐにでも導入できるので、試してみてはいかがでしょうか。
明日は、@komura_cさんです。
参考