この記事はTwilio Developer AdvocateのDominik Kundelがこちらで執筆した記事を日本語化したものになります。
環境変数は、Node.jsアプリケーションから秘匿性の高い情報にアクセスできる、すばらしい方法です。多くのクラウドホスト(Heroku、Azure、AWS、now.shなど)やNode.jsモジュールでは、環境変数を使用します。例を挙げると、ホストではサーバーがどのポートをリッスンすべきかを指定する PORT
変数を設定します。モジュールは NODE_ENV
変数の値によって異なる動作(ロギングなど)をするかもしれません。
この記事では、私がNode.jsで環境変数を扱う際に使用しているTipsやツールをいくつか紹介します。
基本
Node.jsは標準で環境変数へのアクセス方法を提供しています。Node.jsのプロセスが起動すると、グローバルオブジェクトのプロパティとしてenv
オブジェクトを作成し、すでに存在している環境変数へアクセスできます。このオブジェクトを覗いてみたい場合は、node
コマンドでNode.jsのREPL(対話モード)を起動し、次のコマンドを実行します。
console.log(process.env);
このコードは、現在のNode.jsプロセスが認識しているすべての環境変数を出力します。特定の変数にアクセスするには、オブジェクトのプロパティのようにアクセスできます。
console.log('The value of PORT is:', process.env.PORT);
上記のコードを実行しても自分自身のコンピュータではPORT
の値がundefined
と表示されるでしょう。しかし、HerokuやAzureのようなクラウドホストでは、PORT
変数を使用して、ルーティングが正しく動作するためにサーバがどのポートをリッスンすべきかを教えてくれます。したがって、クラウドホストでWebサーバをセットアップする際、最初にPORT
変数を確認しそれを利用するか、またはデフォルト値を渡しリッスンするポートを決定します。
const app = require('http').createServer((req, res) => res.send('Ahoy!'));
const PORT = process.env.PORT || 3000; app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
ハイライトされた行は、環境変数のPORT
が利用可能であればその値を変数の値として、そうでない場合は3000
を待ち受けポートとして使用します。このコードをserver.js
のようなファイルに保存して実行してみてください。
node server.js
出力には、Server is listening on port 3000
というメッセージが表示されます。次にCtrl+C
でサーバーを停止し、以下のコマンドで再起動します。
PORT=9999 node server.js
node
コマンドの前にPORT=9999
と環境変数としてPORT
の値を指定しているため、今回はServer is listening on port 9999
というメッセージが表示されます。
このようにprocess.env
は通常のオブジェクトであるため、値の設定や上書きを簡単に行えます。
process.env.MY_VARIABLE = 'ahoy';
上のコードでは、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モジュールを使うことです。下記のコマンドでインストールできます。
npm install dotenv --save
その後、次の行をエントリファイルの一番上に追加します。
require('dotenv').config();
このコードは、プロジェクトのルートにある.env
ファイルを自動的に読み込み、値を初期化します。すでに設定されている変数は、スキップされます。しかし、本番環境では.env
ファイルを使用せず、それぞれのホストで直接値を設定してください。そのため、ロード文をif文で囲むことになります。
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
このコードでは、サーバーが本番モードで起動していない場合にのみ.env
ファイルを読み込みます。
実際に見てみましょう。さきほどのようにディレクトリにdotenv
をインストールします。同じディレクトリにdotenv-example.js
ファイルを作成し、以下の行を配置します。
console.log('No value for FOO yet:', process.env.FOO);
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
console.log('Now the value for FOO is:', process.env.FOO);
その後、同じディレクトリに.env
ファイルを作成し、次の値を設定します。
FOO=bar
スクリプトを実行しましょう。
node dotenv-example.js
出力は以下のようになります。
No value for FOO yet: undefined
Now the value for FOO is: bar
ご覧のように、値はdotenv
を使用して読み込まれ、定義されます。NODE_ENV
をproduction
に設定して同じコマンドを再実行すると、未定義のままであることが分かります。
NODE_ENV=production node dotenv-example.js
この場合、下記のように出力されます。
No value for FOO yet: undefined
Now the value for FOO is: undefined
実際のコードを変更しない場合は、Nodeの-r
引数を使用してスクリプトを実行する際にdotenv
をロードできます。dotenv-example.js
ファイルを変更します。
console.log('The value for FOO is:', process.env.FOO);
では、まず普通に実行してみましょう。
node dotenv-example.js
このスクリプトは、FOO
の現在の値がundefined
定義であることを表示します。次に、dotenv
を必要とするフラグを立てた上で実行します。
node -r dotenv/config dotenv-example.js
これで.env
ファイルが読み込まれFOO
の値がbar
に設定されました。
dotenvについての詳細は、ドキュメントを確認してみてください。
.env
ファイルを読み込む別の方法
dotenv
はすばらしいのですが、開発中に個人的に気になることがありました。それは、既存の環境変数を上書きせず、またそれを強制もできないことです。
このことを解決し環境変数の読み込みをより便利にするため、dotenv
をベースにした独自のモジュールを作成することにしました。その結果がnode-env-runまたはnodenv
です。これは、
dotenv
を使いenv
ファイルをロード、そして値を初期化後、スクリプトを実行するコマンドラインツールです。
グローバルにインストールできますが、開発とローカル実行を目的として使用することをお勧めします。このツールは下記のコマンドでインストールします。
npm install node-env-run --save-dev
その後、nodenv-example.js
というファイルを作成し、その中に以下のコードを配置します。
console.log('The value for FOO is:', process.env.FOO);
ご覧のように、ここでは何も必要ありません。ただのアプリケーションロジックです。まずはnode
コマンドを使って実行します。
node nodenv-example.js
この実行されたコードはThe value for FOO is: undefined
と出力されます。次にnode-env-run
を使って実行します。
node_modules/.bin/nodenv nodenv-example.js
.envファイルを読み込んでいるのでThe value for FOO is: bar
となります。
node-env-run
は既存の値を上書きできます。最初に上書きをしない場合の動作を確認します。
FOO=foo node_modules/.bin/nodenv nodenv-example.js
出力はThe value for FOO is: foo
となります。次にforce
モードを有効にすると、既存の値を上書きします。
FOO=foo node_modules/.bin/nodenv --force nodenv.js
FOO
が上書きされ、The value for FOO is: bar
と出力されます。
このツールを定期的に使う場合は、npmスクリプトに設定することをお勧めします。package.json
に以下のように追加します。
{
"name": "twilio-blog",
"version": "1.0.0",
"description": "",
"main": "nodenv-example.js",
"scripts": {
"start": "node .",
"start:dev": "nodenv -f ."
},
"author": "",
"license": "ISC",
"devDependencies": {
"node-env-run": "^2.0.1" }
}
このようにして、単純に実行するだけです。
npm run start:dev
node-env-runについての詳細は、ドキュメントを確認してください。
環境変数とnpmスクリプト
npmスクリプトでNode.jsアプリケーションを実行する場合、環境変数の値を確認しておくと便利なシナリオがあります。例えば、開発環境ではnode-env-run
を使用し、本番環境ではnode
を使用したい場合などです。これを非常に簡単にしてくれるツールがif-env
です。
npm install if-env --save
本番環境でも必要になるので、dev dependency
としてインストールしないように注意してください。
インストール後、package.json
ファイルのnpmスクリプトを修正します。
"scripts": {
"start": "if-env NODE_ENV=production ?? npm run start:prod || npm run start:dev",
"start:dev": "nodenv -f .",
"start:prod": "node ."
}
このスクリプトはNODE_ENV
がproduction
と設定されていれば、npm run start:prod
、つまりnode .
を実行します。そうでなければ、npm run start:dev
、つまりnodenv -f
を実行します。
# should output "The value of FOO is: bar"
npm start
# should output "The value of FOO is: undefined"
NODE_ENV=production npm start
if-envについての詳細は、ドキュメントを参照してください。
デバッグ
動作が想定通りに動かない場合や、モジュールが本来の動作をしていない可能性があります。その時こそデバッグを実施します。。私がとても役に立ったことは、環境変数DEBUG
を使って、多くのモジュールの詳細なログを受け取ることでした。例えば、基本的なexpress
サーバーを次のように設定します。
const app = require('express')();
const bodyParser = require('body-parser');
app.use(bodyParser.json());
// for parsing application/json
app.use(bodyParser.urlencoded({ extended: true }));
// for parsing application/x-www-form-urlencoded
app.post('/', (req, res, next) => {
console.log(req);
});
app.listen(3000);
そして、DEBUG
変数を*
に設定して起動します。
DEBUG=* node server.js
以下のような大規模なログの束を受け取ることになります。
この背後にある「魔法」は、debugと呼ばれる軽量モジュールで、その使用方法は非常に簡単です。これを使いたいときは、「名前空間」を初期化します。その後、その名前空間に出力されたログを取得できます。特定の出力を見たい場合は、DEBUG
変数で出力したい名前空間を設定します。例えば、express
routerのすべての出力を見る場合は、適切なワイルドカードを使ってDEBUG
を設定します。
DEBUG=express:router* node server.js
自分が作成する独自のモジュールでdebug
を使用する場合、まずインストールする必要があります。
npm install debug --save
そして、以下のように利用します。
const debug = require('debug')('myApp:someComponent');
debug('Here is a pretty object %o', {
someObject: true });
debugについての詳細は、ドキュメントを確認してください。
すべての環境変数を使用
今回紹介した内容は、環境変数やツールを使ってできることのすべてではなく、私が最もよく使っているものだけです。ほかにも普段使っているすばらしいツールがあれば、ぜひ教えてください。
Node.jsの環境変数について少し分かったところで、Twilio Node.jsクイックスタートを試してみましょう。