LoginSignup
29
13

process.env.NODE_ENV ってなに?

Last updated at Posted at 2020-01-29

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
Node.js
process.env.NODE_ENV
// 'production'

◯ 環境変数 NODE_ENV に指定される値

以下2つが指定されます。

項目 内容
'development' 開発環境のパソコンの NODE_ENV に設定する
'production' 本番環境のサーバーの NODE_ENV に設定する

◯ production と development の違い

公式ドキュメントの和訳です。

production と development の違い

NODE_ENV を production に設定することは一般的に、以下のことを保証します

  • ログ採取は最小限で必要不可欠なレベルに限定されます
  • より高いレベルのキャッシュが導入され、パフォーマンスの最適化が図られます

◯ 環境変数を使うとき

環境変数は、使用するパソコンやサーバによって異なる値を設定したいときに使います。

細かいこと、個人の感想(セキュリティ面)
  • 開発環境と本番環境を識別するとき
    • 開発環境のコードを本番環境にデプロイするとデバッグログがブラウザに表示されてセキュリティがよろしくない状態になることがあります。このような事態を避けるために開発環境には development, 本番環境には production を指定して環境を区別するとよいような気がします。
    • Python のフレームワークである Flask の事例ですが、開発環境のコードをデプロイしてしまい、デバッグ用の SQL を生でブラウザから実行できる画面が表示された状態になり大変なことになったという話を YouTube で聞いたことがあります。
  • パスワードを保存するとき
    • パスワードをソースコードに直接書き込み、GitHub に公開してしまい大変なことになったという話もたまに聞きます。
    • ソースコードを公開しなければパスワードをベタ書きしてもいいんじゃない?って思ったのですが、公開、非公開の有無に関わらずパスワードは環境変数に書きましょうね、というのが一般的なお作法のようです。
    • 考えてみるとソースコードを GitHub で公開しなかったとしてもソースコードにパスワードを書いてしまった場合、git clone するごとにパスワードがいろいろなところに拡散してしまうことになります。環境変数を使い一箇所だけでパスワードを保存しておくほうが安全な気がします(小並感)。

◯ 問題

NODE_ENV に指定される値として一般的でないものは、つぎのうちどれですか?

  1. development
  2. staging
  3. production
解答

2. staging

上記リンクを補足します。なぜ「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

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 をつけ忘れると シェル変数 だけしか変更されず、環境変数 は変更されません。

bash
#
# 1. export をつける
#
export NODE_ENV='development'
echo ${NODE_ENV}
# 'development'

#
# 2. export をつけない
#
APP_ENV='production'  # <--- export をつけなくても
echo ${APP_ENV}
# 'production'          <--- bash では表示されるが...

node
Node.js
process.env.NODE_ENV
// 'development'

process.env.APP_ENV
// undefined           <--- Node.js では表示されず undefined となる

◯ 問題

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. 変数とプロパティ

  1. global 変数
  2. process 変数, global.process プロパティ
  3. process.env プロパティ, global.process.env プロパティ

(1) global 変数

These objects are available in all modules.

global からも参照できる。

bash
export NODE_ENV="production"
node
Node.js
process.env.NODE_ENV
// 'production'

global.process.env.NODE_ENV
// 'production'
補足

この書き方は package.jsonscript プロパティで見ることがあります。

bash
# 環境変数を前置してコマンドを実行することもできます。
NODE_ENV="production" node
Node.js
process.env.NODE_ENV
// 'production'

global.process.env.NODE_ENV
// 'production'

(2) process 変数

process はどこからでも参照できるオブジェクトで global の仲間らしい。

The process object is a global 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 を参照するとエラーになってしまうものは、つぎのうちどれですか?

  1. global.process.env.NODE_ENV
  2. process.env.NODE_ENV
  3. env.NODE_ENV
解答

3. env.NODE_ENV

bash
export NODE_ENV='development'
node
Node.js
env.NODE_ENV
// エラーになる
// Uncaught ReferenceError: env is not defined

4. 型定義

TypeScript をお使いの場合、プロジェクトルート配下に env.d.ts を定義すると process.env に補完が効いて便利です。

env.d.ts
// 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
           }
	    }
    }
}

◯ なんで動くの?

以下の定義を上書きして定義しているから

process.d.ts
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

わからないこと


typescript/lib/lib.dom.d.ts が GitHub のどこにあるのか現在捜索中...

typescript/lib/lib.dom.d.ts
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"
}

◯ そのほか

まだ正直よくわかっていない...

29
13
2

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
29
13