1. なに?
項目 | 内容 |
---|---|
process.env | 環境変数を参照できるオブジェクト |
NODE_ENV | Node.js で、よく使う環境変数の名前 |
#
# 1. 環境変数を設定
#
# (1) Windows - コマンドプロンプト
set NODE_ENV=production
# (2) Windows - PoerShell
$env:NODE_ENV = "production"
# (3) macOS, Ubuntu - bash
export NODE_ENV="production"
#
# 2. Node.js 起動
#
node
process.env.NODE_ENV
// 'production'
◯ 環境変数 NODE_ENV に指定される値
以下2つが指定されます。
項目 | 内容 |
---|---|
'development' | 開発環境のパソコンの NODE_ENV に設定する |
'production' | 本番環境のサーバーの NODE_ENV に設定する |
◯ production と development の違い
公式ドキュメントの和訳です。
NODE_ENV を production に設定することは一般的に、以下のことを保証します
- ログ採取は最小限で必要不可欠なレベルに限定されます
- より高いレベルのキャッシュが導入され、パフォーマンスの最適化が図られます
◯ 環境変数を使うとき
環境変数は、使用するパソコンやサーバによって異なる値を設定したいときに使います。
細かいこと、個人の感想(セキュリティ面)
- 開発環境と本番環境を識別するとき
- 開発環境のコードを本番環境にデプロイするとデバッグログがブラウザに表示されてセキュリティがよろしくない状態になることがあります。このような事態を避けるために開発環境には
development
, 本番環境にはproduction
を指定して環境を区別するとよいような気がします。 - Python のフレームワークである Flask の事例ですが、開発環境のコードをデプロイしてしまい、デバッグ用の SQL を生でブラウザから実行できる画面が表示された状態になり大変なことになったという話を YouTube で聞いたことがあります。
- 開発環境のコードを本番環境にデプロイするとデバッグログがブラウザに表示されてセキュリティがよろしくない状態になることがあります。このような事態を避けるために開発環境には
- パスワードを保存するとき
- パスワードをソースコードに直接書き込み、GitHub に公開してしまい大変なことになったという話もたまに聞きます。
- ソースコードを公開しなければパスワードをベタ書きしてもいいんじゃない?って思ったのですが、公開、非公開の有無に関わらずパスワードは環境変数に書きましょうね、というのが一般的なお作法のようです。
- 考えてみるとソースコードを GitHub で公開しなかったとしてもソースコードにパスワードを書いてしまった場合、git clone するごとにパスワードがいろいろなところに拡散してしまうことになります。環境変数を使い一箇所だけでパスワードを保存しておくほうが安全な気がします(小並感)。
◯ 問題
NODE_ENV
に指定される値として一般的でないものは、つぎのうちどれですか?
- development
- staging
- production
解答
2. staging
- ステージング環境 -「分かりそう」で「分からない」でも「分かった」気になれる...
- NODE_ENV に development と production 以外を入れると辛い
上記リンクを補足します。なぜ「NODE_ENV に development と production 以外を入れると辛」くなるのでしょうか?
自分が作っているアプリは NODE_ENV
を参照します。一方で、例えば Next.js や Nuxt と言ったフレームワークも NODE_ENV
を参照します。
フレームワークは NODE_ENV
には development
または production
が代入されていることを前提に動作しています。もし勝手に NODE_ENV
に例えば staging
を設定してしまった場合、フレームワークが動作しなくなります。
もし staging
を定義したい場合は、別途自分のアプリ専用の環境変数、例えば APP_ENV
のような環境変数を定義すればよいのかなと思いました(小並感)。
環境 | NODE_ENV | APP_ENV |
---|---|---|
開発 | development | development |
ステージング | production | staging |
本番 | production | production |
NODE_ENV=productionが最適化のために使われてるので、NODE_ENV=stagingのような使い方はしないで別の名前の環境変数を使おうという話。 "NODE ENV=production is a lie - YouTube" https://t.co/7uCLayNlTy #nodejs #video
— azu (@azu_re) November 17, 2023
2. 環境変数
↓ 環境変数という単語を知らないとこの先の理解が厳しいかもしれません...
- 環境変数 -「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
(1) Windows - コマンドプロンプト
# 設定
set NODE_ENV=production
# 表示
echo %NODE_ENV%
# 一覧の表示
set
(2) Windows - PowerShell
# 設定
$env:NODE_ENV = "production"
# 表示
echo $Env:NODE_ENV
# 一覧の表示
Get-ChildItem Env:
(3) macOS, Ubuntu - bash, zsh
# 設定
export NODE_ENV="production"
# 表示
echo ${NODE_ENV}
# 一覧の表示
env
◯ 環境変数とシェル変数を区別する
環境変数とシェル変数の違い | |
---|---|
Windows - コマンドプロンプト | なし *1 |
Windows - PowerShell | あり |
macOS, Ubuntu - bash, zsh | あり |
補足 *1
Windows - コマンドプロンプトではすべて環境変数として扱われます。例えば export
コマンドは環境変数を設定するためのものです。export
をつけ忘れると シェル変数 だけしか変更されず、環境変数 は変更されません。
#
# 1. export をつける
#
export NODE_ENV='development'
echo ${NODE_ENV}
# 'development'
#
# 2. export をつけない
#
APP_ENV='production' # <--- export をつけなくても
echo ${APP_ENV}
# 'production' <--- bash では表示されるが...
node
process.env.NODE_ENV
// 'development'
process.env.APP_ENV
// undefined <--- Node.js では表示されず undefined となる
「この書き方だと別のシェルで実行?」「でもexportだからこれは環境変数…大丈夫か」「ん?でもechoすると空?」「どうなってるんだ?」などと、いちいち初歩の初歩のところ(だということはわかる)で躓いていて進まない。スマホでアプリ切替ができないご老人みたい。簡単スマホならぬLinuxほしい。
— あや@ほわほわ (@aya_howa) December 14, 2023
◯ 問題
Node.js で process.env.NODE_ENV
と打ち込むと development
と表示されるようにするには、つぎのうちどれを選べばよいですか?環境は bash, zsh であるとします。
# これでは表示されない
NODE_ENV="development"
# 1
set NODE_ENV="development"
# 2
$env:NODE_ENV = "development"
# 3
export NODE_ENV="development"
解答
# 3
export NODE_ENV="development"
3. 変数とプロパティ
-
global
変数 -
process
変数,global.process
プロパティ -
process.env
プロパティ,global.process.env
プロパティ
(1) global 変数
These objects are available in all modules.
global
からも参照できる。
export NODE_ENV="production"
node
process.env.NODE_ENV
// 'production'
global.process.env.NODE_ENV
// 'production'
補足
この書き方は package.json
の script
プロパティで見ることがあります。
# 環境変数を前置してコマンドを実行することもできます。
NODE_ENV="production" node
process.env.NODE_ENV
// 'production'
global.process.env.NODE_ENV
// 'production'
(2) process 変数
process
はどこからでも参照できるオブジェクトで global
の仲間らしい。
The
process
object is aglobal
that provides information about, and control over, the current Node.js process. As a global, it is always available to Node.js applications without using require(). It can also be explicitly accessed using require():const process = require('process');
(3) process.env プロパティ
process.env
は環境変数を持っている。
The process.env property returns an object containing the user environment. See environ(7).
◯ 問題
NODE_ENV
を参照するとエラーになってしまうものは、つぎのうちどれですか?
global.process.env.NODE_ENV
process.env.NODE_ENV
env.NODE_ENV
解答
3. env.NODE_ENV
export NODE_ENV='development'
node
env.NODE_ENV
// エラーになる
// Uncaught ReferenceError: env is not defined
4. 型定義
TypeScript をお使いの場合、プロジェクトルート配下に env.d.ts
を定義すると process.env
に補完が効いて便利です。
// 1. プロジェクトのルートディレクトリに
// env.d.ts ファイルを作成
// 2. コピペで貼り付け
declare module 'process' {
global {
namespace NodeJS {
interface ProcessEnv {
readonly NODE_ENV?: "development" | "production"
readonly BACKEND_URL?: string
readonly DATABASE_URL?: string
}
}
}
}
◯ なんで動くの?
以下の定義を上書きして定義しているから
declare module "process" {
// 中略
global {
var process: NodeJS.Process; // <--- process 変数
// NodeJS.Process という表記は
// NodeJS という namespace の中の
// Process という型ということでしょうか?
namespace NodeJS {
// 中略
// env.d.ts は
// どうもここの定義を上書きして定義をしているらしい...
interface ProcessEnv extends Dict<string> {
/**
* Can be used to change the default timezone at runtime
*/
TZ?: string;
}
// 中略
interface Process extends EventEmitter { // <--- NodeJS.Process
// 中略
env: ProcessEnv; // <--- env プロパティ
// 中略
}
}
}
}
以下のページで教わりました。誠にありがとうございます。
注意
正直、なんで動くのか、書いている本人も理解はしていません...
調べたことを以下にまとめていきます。
(1) .d.ts ファイル
わかっていること
コンパイラは適切なパスに従って、.ts、.tsxを見つけようとし、次に.d.tsを探します。 もし特定のファイルが見つからなかった場合、コンパイラはambientモジュール宣言を探し、 .d.tsファイル内にある必要な宣言を呼び戻します。
名前空間(namespace)とモジュール - js STUDIO
(2) declare module
わかっていること
(3) global
わからないこと
Remember folks, declaring globals isn't that hard. pic.twitter.com/st1ZJfFRMk
— Matt Pocock (@mattpocockuk) January 10, 2024
typescript/lib/lib.dom.d.ts
が GitHub のどこにあるのか現在捜索中...
declare var window: Window & typeof globalThis;
interface Window {
dataLayer: object[];
}
window.dataLayer.push({ event: "event_name" });
(4) namespace NodeJS
わからないこと
uhyo さんの記事を読んでも namespace
が、なにやってるかわからない...orz
(5) interface
interface
を使えば型を上書きできる。type
ではできない。
interface Person {
name: string
}
interface Person {
email: string
}
// name と email 両方必要になる
const john: Person = {
name: "john",
email: "hoge@example.com"
}
◯ そのほか
まだ正直よくわかっていない...