LoginSignup
14
8

More than 5 years have passed since last update.

Angular 4 で Connection String や Secret を Environment Variables から取得する

Last updated at Posted at 2017-10-18

The twelve-factor app にある通り、環境依存の情報は、環境変数から設定するようにしたい。しかし、SPA の Angular とかだったらどうするんだろう?きっとこれは基礎的なことなのだけど、意外と自分には難しかったので、今まで学んだことを自分のために、ブログにしておきたい。

Environment Variables を Angular (4) から使う

ベストプラクティス的なものがないのかなぁ。と色々調べて見たけど、Facebook でなきを入れていたらヒントをもらえた。

Screen Shot 2017-10-18 at 7.20.37 PM.png

環境変数を取り込む仕組みのあれこれ。

ちなみに、Angular では、環境変数は取り込めない。よくよく考えると、SPA は、ブラウザにダウンロードされて使うのだから、そらそうだ。

上記の記事を読んでいると、どうやら、Angular には、environment という仕組みがあるらしい。そのenvironmentを環境によって変えられる様子。

src/environments/
├── environment.prod.ts
└── environment.ts

ここを、プロジェクトをビルドする時に切り替える。例えばこんな感じ。

_environment.prod.ts

export const environment = {
  production: true,
  hostUrl: "http://some.prod"
};

_environment.ts

export const environment = {
  production: false,
  hostUrl: "http://some.dev"
}

app.component.html に 下記のコードを入れておく。

<h2> ServerName: {{hostUrl}}</h2>
$ ng serve 

Screen Shot 2017-10-18 at 7.41.04 PM.png

だと、デフォルトが起動する。

$ ng serve --environment prod

Screen Shot 2017-10-18 at 7.41.58 PM.png

これでプロダクションが起動した。

環境変数を埋め込む

少なくとも Angular CLIを使っている時はこの方式で行けそう。いきなり本物のプロジェクトに盛り込むより、プロジェクトを生成してみよう。

$ ng new host-inject

この状態から、環境変数を取り込んで見たい。環境変数は Angular では直接取り込めない。色々読んでいると、ビルド時に、プリコンパイルして盛り込むというのが良さげ。

NOTE: 最初、process.env を直接実行しようとしたけど、これは見つかららないと言われる。ちなみにこれは、tsconfig.app.json の下記の部分を追加すると、解消された。

"CompilerOptions": {
  typs["node"],
    :
}

scripts/prebuild.ts というファイルを作ってみる。 テンプレート environment.ts.template を元に、環境変数を取り込んで作成をするシンプルなもの。

import * as fs from 'fs';
import * as path from 'path';
import * as ejs from 'ejs';

const environmentFilesDirectory = path.join(__dirname, '../src/environments');
const targetEnvironmentTemplateFileName = 'environment.ts.template';
const targetEnvironemntFileName = 'environment.ts';

const defaultEnvValues = {
    SOME_HOST: "http://default.com"
}

const environmentTemplate = fs.readFileSync(
    path.join(environmentFilesDirectory, targetEnvironmentTemplateFileName),
    {encoding: 'utf-8'}
);
let obj:any = (<any>Object).assign({}, defaultEnvValues, process.env);
const output = ejs.render(environmentTemplate, obj);
fs.writeFileSync(path.join(environmentFilesDirectory, targetEnvironemntFileName), output);
process.exit(0);

ちなみに、(<any>Object).assign の部分は当初、Object に assign が見つからないと怒られた。<any> をつけて解決。

enviornment.ts.template

export const environment = {
  production: false,
  hostUrl: "<%= SOME_HOST %>"
};

これを実行するために、package.json に、

"prebuild": "tsc scripts/prebuild.ts && node scripts/prebuild.js",

を追加した。

プリビルドする。

$ npm run prebuild

しっかり、ファイルがジェネレートされた。

$ env
SOME_HOST=http://some.com

environment.ts

export const environment = {
  production: false,
  hostUrl: "http://some.com"
};

バッチリできている。先ほど紹介してもらった記事を見ても、ジェネレートする方法が一番スッキリきた。

本当にこの方式で問題ないのか?

問題は、この方式だと、結局のところ、ブラウザから URL が見れちゃったりするんじゃないの?と思ったが、意外に見えないようだ。もちろん、enviornments の下をうっかり公開する設定にしてないことが大切だとは思うが。よく、SPA を Blob Storage に置くとかの例があるが、ああいうのはどうしているんだろう。Azure Functions Proxy などで制限する感じだろうか。次はその辺をやってみたい。

ちなみに、全てのソースコードはこちらに置いています。

Resource

14
8
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
14
8