Node.jsで環境変数を利用する方法
Time to read:
環境変数は、Node.jsアプリケーションから秘匿性の高い情報にアクセスできる、すばらしい方法です。多くのクラウドホスト(Heroku、Azure、AWS、now.shなど)やNode.jsモジュールでは、環境変数を使用します。例を挙げると、ホストではサーバーがどのポートをリッスンすべきかを指定する PORT 変数を設定します。モジュールは NODE_ENV 変数の値によって異なる動作(ロギングなど)をするかもしれません。
この記事では、私がNode.jsで環境変数を扱う際に使用しているTipsやツールをいくつか紹介します。
基本
Node.jsは標準で環境変数へのアクセス方法を提供しています。Node.jsのプロセスが起動すると、グローバルオブジェクトのプロパティとしてenvオブジェクトを作成し、すでに存在している環境変数へアクセスできます。このオブジェクトを覗いてみたい場合は、nodeコマンドでNode.jsのREPL(対話モード)を起動し、次のコマンドを実行します。
このコードは、現在のNode.jsプロセスが認識しているすべての環境変数を出力します。特定の変数にアクセスするには、オブジェクトのプロパティのようにアクセスできます。
上記のコードを実行しても自分自身のコンピュータではPORTの値がundefinedと表示されるでしょう。しかし、HerokuやAzureのようなクラウドホストでは、PORT変数を使用して、ルーティングが正しく動作するためにサーバがどのポートをリッスンすべきかを教えてくれます。したがって、クラウドホストでWebサーバをセットアップする際、最初にPORT変数を確認しそれを利用するか、またはデフォルト値を渡しリッスンするポートを決定します。
ハイライトされた行は、環境変数のPORTが利用可能であればその値を変数の値として、そうでない場合は3000を待ち受けポートとして使用します。このコードをserver.jsのようなファイルに保存して実行してみてください。
出力には、Server is listening on port 3000というメッセージが表示されます。次にCtrl+Cでサーバーを停止し、以下のコマンドで再起動します。
nodeコマンドの前にPORT=9999と環境変数としてPORTの値を指定しているため、今回はServer is listening on port 9999というメッセージが表示されます。
このようにprocess.envは通常のオブジェクトであるため、値の設定や上書きを簡単に行えます。
上のコードでは、MY_VARIABLEの値を設定、または上書きします。しかしこの値は現在のNode.jsプロセスの実行中に設定されたため、現在のプロセスとその子プロセスのみで利用可能である点に注意してください。全体として環境変数をオーバーライドすることは回避し、PORTの例で示したように環境変数を変数に代入する、あるいはその変数を初期化して利用すべきでしょう。
.env ファイルから変数をロード
複数の異なるNode.jsプロジェクトを1台のコンピュータで開発する場合、環境変数名が重複していることに気付くでしょう。例えば、別々のメッセージングアプリケーションで異なるTwilio Messaging Service SIDが必要な場合を考えてみましょう。両方ともTWILIO_MESSAGE_SERVICE_SIDという名前で定義されているというシナリオです。それぞれのプロジェクトで固有の設定を実現する方法として、.envファイルを使用できます。このファイルでは、さまざまな環境変数とその値を指定できます。
このファイルは機密性の高い情報が、ソースコントロールにチェックインチェックすべきではありません。そこで.envを.gitignoreに追加しましょう。多くのTwilioデモアプリケーションで見かける.env.exampleファイルは、.envファイルにコピーし、値を設定することを想定しています。テンプレートファイルをプロジェクトの他のメンバーと共有する場合は、今回のようなファイルを用意します。
さて、このファイルから値を読み込むにはどうすればよいでしょうか。最も簡単な方法は、[dotenv](http://npm.im/dotenv)というnpmモジュールを使うことです。下記のコマンドでインストールできます。
その後、次の行をエントリファイルの一番上に追加します。
このコードは、プロジェクトのルートにある.envファイルを自動的に読み込み、値を初期化します。すでに設定されている変数は、スキップされます。しかし、本番環境では.envファイルを使用せず、それぞれのホストで直接値を設定してください。そのため、ロード文をif文で囲むことになります。
このコードでは、サーバーが本番モードで起動していない場合にのみ.envファイルを読み込みます。
実際に見てみましょう。さきほどのようにディレクトリにdotenvをインストールします。同じディレクトリにdotenv-example.jsファイルを作成し、以下の行を配置します。
その後、同じディレクトリに.envファイルを作成し、次の値を設定します。
スクリプトを実行しましょう。
出力は以下のようになります。
ご覧のように、値はdotenvを使用して読み込まれ、定義されます。NODE_ENVをproductionに設定して同じコマンドを再実行すると、未定義のままであることが分かります。
この場合、下記のように出力されます。
実際のコードを変更しない場合は、Nodeの-r引数を使用してスクリプトを実行する際にdotenvをロードできます。dotenv-example.jsファイルを変更します。
では、まず普通に実行してみましょう。
このスクリプトは、FOOの現在の値がundefined定義であることを表示します。次に、dotenvを必要とするフラグを立てた上で実行します。
これで.envファイルが読み込まれFOOの値がbarに設定されました。
dotenvについての詳細は、ドキュメントを確認してみてください。
.envファイルを読み込む別の方法
dotenvはすばらしいのですが、開発中に個人的に気になることがありました。それは、既存の環境変数を上書きせず、またそれを強制もできないことです。
このことを解決し環境変数の読み込みをより便利にするため、dotenvをベースにした独自のモジュールを作成することにしました。その結果がnode-env-runまたはnodenvです。これは、dotenvを使いenvファイルをロード、そして値を初期化後、スクリプトを実行するコマンドラインツールです。
グローバルにインストールできますが、開発とローカル実行を目的として使用することをお勧めします。このツールは下記のコマンドでインストールします。
その後、nodenv-example.jsというファイルを作成し、その中に以下のコードを配置します。
ご覧のように、ここでは何も必要ありません。ただのアプリケーションロジックです。まずはnodeコマンドを使って実行します。
この実行されたコードはThe value for FOO is: undefinedと出力されます。次にnode-env-runを使って実行します。
.envファイルを読み込んでいるのでThe value for FOO is: barとなります。
node-env-runは既存の値を上書きできます。最初に上書きをしない場合の動作を確認します。
出力はThe value for FOO is: fooとなります。次にforceモードを有効にすると、既存の値を上書きします。
FOOが上書きされ、The value for FOO is: barと出力されます。
このツールを定期的に使う場合は、npmスクリプトに設定することをお勧めします。package.jsonに以下のように追加します。
このようにして、単純に実行するだけです。
node-env-runについての詳細は、ドキュメントを確認してください。
環境変数とnpmスクリプト
npmスクリプトでNode.jsアプリケーションを実行する場合、環境変数の値を確認しておくと便利なシナリオがあります。例えば、開発環境ではnode-env-runを使用し、本番環境ではnodeを使用したい場合などです。これを非常に簡単にしてくれるツールがif-envです。
本番環境でも必要になるので、dev dependencyとしてインストールしないように注意してください。
インストール後、package.jsonファイルのnpmスクリプトを修正します。
このスクリプトはNODE_ENVがproductionと設定されていれば、npm run start:prod、つまりnode .を実行します。そうでなければ、npm run start:dev、つまりnodenv -fを実行します。
if-envについての詳細は、ドキュメントを参照してください。
デバッグ
動作が想定通りに動かない場合や、モジュールが本来の動作をしていない可能性があります。その時こそデバッグを実施します。。私がとても役に立ったことは、環境変数DEBUGを使って、多くのモジュールの詳細なログを受け取ることでした。例えば、基本的なexpressサーバーを次のように設定します。
そして、DEBUG変数を*に設定して起動します。
以下のような大規模なログの束を受け取ることになります。
この背後にある「魔法」は、debugと呼ばれる軽量モジュールで、その使用方法は非常に簡単です。これを使いたいときは、「名前空間」を初期化します。その後、その名前空間に出力されたログを取得できます。特定の出力を見たい場合は、DEBUG変数で出力したい名前空間を設定します。例えば、express routerのすべての出力を見る場合は、適切なワイルドカードを使ってDEBUGを設定します。
自分が作成する独自のモジュールでdebugを使用する場合、まずインストールする必要があります。
そして、以下のように利用します。
debugについての詳細は、ドキュメントを確認してください。
すべての環境変数を使用
今回紹介した内容は、環境変数やツールを使ってできることのすべてではなく、私が最もよく使っているものだけです。ほかにも普段使っているすばらしいツールがあれば、ぜひ教えてください。
Node.jsの環境変数について少し分かったところで、Twilio Node.jsクイックスタートを試してみましょう。