10yroの開発日記

株式会社10yro(トイロ)のエンジニアが書いています

【Angular】システム変更通知

SPA アプリケーションにおいてシステムアップデート(デプロイ)した際に

キャッシュのファイルを参照しており更新されないケースを想定し、

ユーザにキャッシュしているファイルを更新してほしい旨通知する方法を記載します。


今回やることはrevision管理用ファイル(何らかの設定ファイル)にrevisionを記載しておき

システム起動時にその時のrevisionを保持しておきます。

そして、任意のタイミングでそのファイルのrevisionを確認し、変更されていたらユーザにその旨通知するという内容となります。


手順としては以下となります。



1. revision 保持用のrevisionファイルを用意 (json 等)

以下のような設定ファイルを追加します。

assets/application.config.json

{
    "revision": "b2a91a752e068ccf4a3b0f4759d66ec096c14821"
}

2. revisionファイルからrevisionを取得

revision 管理用の Serviceを作成し、取得用の関数を追加する。

revision.service.ts

revision : string | null = null;  // ※今のrevisionを保持する変数やLocal strage 等を用意

get(): Observable<string | null> {
    let hash = new Date().getTime();
    return this.http.get('assets/application.config.json?' + hash).pipe(
        map((conf: any) => {
            return conf['revision'] ?? null;
        })
    );
}

set(): void {
    this.get().subscribe((rev) => {
        this.revision = rev;
    });
}

また、このServiceはベースのコンポーネントでinjectし、setしておきます。

これにより、システム起動時、リロード時などベースコンポーネントが更新されるタイミングで

最新のrevisionがセットされるため画面のファイルキャッシュ状態と合わせておきます。

app.component.ts

export class AppComponent {
    constructor(
        private revision: RevisionService,
        ...
    ) {
        revision.set();
    }
}

3. 任意のタイミング(画面遷移時 等)で再度revisionファイルを確認する。

今回は画面遷移時にチェックしたいので

Routing moduleにチェック処理を追加します。

layout-routing.module.ts

constructor(
    private revision: RevisionService,
    private router: Router
) {
    this.router.events
        .pipe(filter((e: Event): e is RouterEvent => e instanceof RouterEvent))
        .subscribe((e: RouterEvent) => {
            if (e instanceof NavigationEnd) {
                // チェック処理を追加 ※↓のisRevised() は (4)にて追加する。
                this.revision.isRevised();
            }
        });
}

4. 変更があればAlert等ユーザに通知

先ほどのrevision serviceにチェック処理を追加する。

revision.service.ts

this.get().subscribe((rev) => {
    if (this.revision != rev) {
        this.notifyRevised();
    }
});

notifyRevised(): void {
    // Alert を出すなどユーザに通知
    // 例)「システムがアップデートされました。画面をリロードしてください。」メッセージ出力
}