適切なタイトルかどうかは不安です..
angular-cli を使っていて environment.ts
など設定のためのインタフェースはいくつか見つけたのですが ng build
した後の dist
に対して設定する方法が見つからなくて、探すより早く実装できそうだったので、試しにやってみました、という話です。
もう少し具体的な動機を言うと docker run -v <config-file>
のように設定ファイルを上書きして実行できる docker イメージを作ってみたかったからです。docker の nginx
イメージに dist
のみを乗っけたものをアプリケーションのイメージとした時に、その方法で設定を行うように実装する方法はないものか、模索していました。
今回の方針としては、 ng build
では src/assets/
以下がそのまま dist/assets
にコピーされるようなので、その配下にスクリプトを置いて実行時設定として利用することにします。
グローバルに設定オブジェクト appRuntimeConfig
を定義するスクリプトを用意します。
const appRuntimeConfig = {
apiRoot: 'http://localhost:9090',
message: 'overwritten by runtime-config.js',
}
それを index.html
で読み込み
<html>
<head>
:
<!-- Runtime Config -->
<script src="assets/runtime-config.js"></script>
</head>
:
グローバルの appRuntimeConfig
を参照して取り込むサービスを定義します。
import { Injectable } from '@angular/core';
// 一応インタフェース定義
interface RuntimeConfig {
apiRoot: string;
message: string;
}
// グローバル変数を declare 宣言
declare const appRuntimeConfig: Partial<RuntimeConfig>;
@Injectable()
export class ConfigService {
// デフォルト設定
runtime: RuntimeConfig = {
apiRoot: 'http://localhost:8080',
message: 'will be overwritten',
};
constructor() {
// appRuntimeConfig 未定義状態を回避する
if (typeof appRuntimeConfig !== 'undefined') {
// デフォルト設定に上書き
Object.assign(this.runtime, appRuntimeConfig);
}
}
}
これで、ConfigService
をモジュール定義で provider として登録すれば他のコンポーネントから楽に参照できるようになります。
export class AppComponent {
title = 'app works!';
constructor(private config: ConfigService) {
console.log(config);
// => {
// runtime: {
// apiRoot: "http://localhost:9090",
// message: "overwritten by runtime-config.js",
// }
// }
}
}
これで例えば ng build
した dist/
配下を /app/
に置いた docker イメージを作った場合 docker run
で /app/assets/runtime-config.js
を上書きすれば実行時設定ができるようになりますね。
ng new
した状態からの変更点を github で見られるようにしましたので、よろしければご覧ください。