これは、なにをしたくて書いたもの?
Node.jsで環境変数をファイルから読み込むことができるdotenvというものがあるらしいので、試してみることにしました。
dotenv
dotenvをベースにしているdotenv-vaultというプロダクトのWebサイトを見ると、
Simplify Your Secrets | Dotenv
dotenvはNode.js以外にも存在しているようです。
今回はNode.js向けのdotenvのみにフォーカスします。
使い方としては、.env
というファイルを作成して
.env
S3_BUCKET="YOURS3BUCKET" SECRET_KEY="YOURSECRETKEYGOESHERE"
dotenvモジュールをインポートすればよいみたいです。
require('dotenv').config() console.log(process.env) // remove this after you've confirmed it is working
あとはprocess.env.[環境変数名]
で環境変数が参照できるようになります。
複数行の記述もできるようです。
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY----- ... Kh9NV... ... -----END RSA PRIVATE KEY-----"
--require
(または-r
)オプションで、プリロードすることもできるようです。
$ node -r dotenv/config your_script.js
オプションをコマンドライン引数で指定したり
$ node -r dotenv/config your_script.js dotenv_config_path=/custom/path/to/.env dotenv_config_debug=true
環境変数で指定することもできるようです。
$ DOTENV_CONFIG_<OPTION>=value node -r dotenv/config your_script.js $ DOTENV_CONFIG_ENCODING=latin1 DOTENV_CONFIG_DEBUG=true node -r dotenv/config your_script.js dotenv_config_path=/custom/path/to/.env
とりあえず、試していってみることにしましょう。
環境
今回の環境は、こちら。
$ node --version v18.16.1 $ npm --version 9.5.1
dotenvを使ってみる
では、dotenvを使ってみましょう。
Node.jsプロジェクトを作成。
$ npm init -y $ npm i -D prettier
Prettierも入れています。
"devDependencies": { "prettier": "^2.8.8" },
.prettierrc.json
{ "singleQuote": true, "printWidth": 120 }
とりあえず、環境変数を標準出力に書き出すJavaScriptを書いてみます。
print-env.js
console.log(`get env: MY_ENV_VAR = ${process.env.MY_ENV_VAR}`);
実行。
$ node print-env.js get env: MY_ENV_VAR = undefined
この状態だと環境変数を設定していないので当然undefined
です。
環境変数を設定すれば当然ながら参照します。
$ MY_ENV_VAR=Hello node print-env.js get env: MY_ENV_VAR = Hello
これでもいいのですが、環境変数が複数あったり使用する値を切り替えたかったりすると煩雑になってきますね。
こういう時にdotenvを使うとよいのだろうと思います。
というわけで、dotenvをインストール。
$ npm i dotenv
インストールされたdotenvのバージョン。
"dependencies": { "dotenv": "^16.3.1" }
使い方としては、まずは.env
というファイルを用意するようです。
.env
MY_ENV_VAR=Hello from dotenv
次に、先ほどのJavaScriptファイルにdotenvのロードを追加します。
print-env.js
require('dotenv').config(); console.log(`get env: MY_ENV_VAR = ${process.env.MY_ENV_VAR}`);
これで実行すると、.env
ファイルに設定した内容を環境変数に追加してくれます。
$ node print-env.js get env: MY_ENV_VAR = Hello from dotenv
明示的な追加が必要なので、dotenvをロードしている部分をコメントアウトすると
print-env.js
// require('dotenv').config(); console.log(`get env: MY_ENV_VAR = ${process.env.MY_ENV_VAR}`);
.env
ファイルを読み込まなくなります。
$ node print-env.js get env: MY_ENV_VAR = undefined
個人的にはこの「ソースコードにdotenvの使用を明示的に追加する」という方法はちょっと嫌なので、
Node.jsの--require
(-r
)オプションを使ったプリロードの方が良いかなと思います。
コンテナ環境とかだと、環境変数はコンテナ側の設定で行うことが多いと思いますし。
こうすると、ソースコードにdotenvのロードを書かなくとも動作させることができます。
$ node -r dotenv/config print-env.js get env: MY_ENV_VAR = Hello from dotenv
ちなみに、.env
ファイルに書かれている環境変数がすでに存在した場合は、あらかじめ環境変数として定義されている値が優先される
ようです。
$ MY_ENV_VAR=Hello node -r dotenv/config print-env.js get env: MY_ENV_VAR = Hello
読み込むファイルを切り替える
dotenvはデフォルトで.env
というファイルを読み込みますが、これを別のファイルに切り替えることができます。
こんなファイルを用意。
.env-other
MY_ENV_VAR=Hello from dotenv other
dotenvの設定は、コマンドラインオプションでdotenv_config_<option>=value
と指定するか、
環境変数でDOTENV_CONFIG_<OPTION>=value
で指定することができます。
今回は環境変数を使いましょう。読み込むファイルを.env
以外にするにはDOTENV_CONFIG_PATH
環境変数を指定します。
確認。
$ DOTENV_CONFIG_PATH=.env-other node -r dotenv/config print-env.js get env: MY_ENV_VAR = Hello from dotenv other
読み込むファイルが切り替わりました。
コメントや複数行の環境変数を書く
dotenvで読み込むファイルには、コメントを書いたり、環境変数を複数行で定義できたりします。
複数行の環境変数を定義するには、"
または'
で囲って複数行で書きます。コメントは#
で書けばOKです。
こんな感じですね。
.env-multiple
# これは、シンプルな環境変数定義です MY_ENV_VAR=Hello World!! # これは、複数行の環境変数定義です MY_ENV_MULTILINE_VAR="begin \"クォートは\でエスケープして記述\" end"
読み込むソースコード。
print-env-multiple.js
console.log(`get env: MY_ENV_VAR = ${process.env.MY_ENV_VAR}`); console.log(); console.log(`get env: MY_ENV_MULTILINE_VAR = ${process.env.MY_ENV_MULTILINE_VAR}`);
確認。
$ DOTENV_CONFIG_PATH=.env-multiple node -r dotenv/config print-env-multiple.js get env: MY_ENV_VAR = Hello World!! get env: MY_ENV_MULTILINE_VAR = begin \"クォートは\でエスケープして記述\" end
OKですね。
Jestと組み合わせる
最後は、dotenvをJestを組み合わせて使ってみましょう。
新しくNode.jsプロジェクトを作成。
$ npm init -y $ npm i -D prettier $ npm i dotenv $ npm i -D jest
依存関係は、こんな感じになりました。
"devDependencies": { "jest": "^29.5.0", "prettier": "^2.8.8" }, "dependencies": { "dotenv": "^16.3.1" }
scripts
はこうしておきます。
"scripts": { "format": "prettier --write **/*.js", "test": "jest" },
.env
ファイルを用意。
.env
MY_ENV_VAR=Hello dotenv
テストコード。
use-dotenv.test.js
test('use dotenv', () => { expect(process.env.MY_ENV_VAR).toBe('Hello dotenv'); });
このテストはこのまま実行しても失敗します。
$ npm run test > dot-env-jest-example@1.0.0 test > jest FAIL ./use-dotenv.test.js ✕ use dotenv (4 ms) ● use dotenv expect(received).toBe(expected) // Object.is equality Expected: "Hello dotenv" Received: undefined 1 | test('use dotenv', () => { > 2 | expect(process.env.MY_ENV_VAR).toBe('Hello dotenv'); | ^ 3 | }); 4 | at Object.toBe (use-dotenv.test.js:2:34) Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 0.288 s, estimated 1 s Ran all test suites.
こうすれば動作しますが、それもちょっと違う気がします…。
use-dotenv.test.js
require('dotenv').config(); test('use dotenv', () => { expect(process.env.MY_ENV_VAR).toBe('Hello dotenv'); });
どうしたらいいかですが、Jestの設定ファイルでsetupFiles
というものを使えば良さそうです。
dotenvを使う分にはでもよさそうでしたが。
Configuring Jest / setupFilesAfterEnv
設定。
jest.config.js
module.exports = { setupFiles: ['dotenv/config'], testEnvironment: 'node', };
これでdotenvが動作するようになります。
$ npm run test > dot-env-jest-example@1.0.0 test > jest PASS ./use-dotenv.test.js ✓ use dotenv (3 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 0.236 s, estimated 1 s Ran all test suites.
別のファイルを読み込ませたい場合は
.env-other
MY_ENV_VAR=Hello dotenv other
環境変数の指定をscripts
に含めればよいのかな、と。
"scripts": { "format": "prettier --write **/*.js", "test": "jest", "test-other": "DOTENV_CONFIG_PATH=.env-other jest" },
確認。
$ npm run test-other > dot-env-jest-example@1.0.0 test-other > DOTENV_CONFIG_PATH=.env-other jest FAIL ./use-dotenv.test.js ✕ use dotenv (4 ms) ● use dotenv expect(received).toBe(expected) // Object.is equality Expected: "Hello dotenv" Received: "Hello dotenv other" 2 | 3 | test('use dotenv', () => { > 4 | expect(process.env.MY_ENV_VAR).toBe('Hello dotenv'); | ^ 5 | }); 6 | at Object.toBe (use-dotenv.test.js:4:34) Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 0.251 s, estimated 1 s Ran all test suites.
こんなところでしょうか。
オマケ
最後に少しdotenvのソースコードを眺めておきます。
小さなライブラリーなので、中身を見るのもそう苦労しないでしょう。
オプションを環境変数およびコマンドラインオプションから解決している部分。
https://github.com/motdotla/dotenv/blob/v16.3.1/config.js
https://github.com/motdotla/dotenv/blob/v16.3.1/lib/env-options.js
https://github.com/motdotla/dotenv/blob/v16.3.1/lib/cli-options.js
.env
ファイルのパース。
https://github.com/motdotla/dotenv/blob/v16.3.1/lib/main.js#L12-L48
まとめ
Node.jsで環境変数をファイルから読み込むdotenvを試してみました。
なんとなくこういうものがあるというのは知っていましたが、実際に使ったことはなかったので確認しておいてよかったです。
他の言語にも同じようなものがあることもわかりましたし。