Vite で「process is not defined」が解決できない
ブラウザには Node のグローバル process が無いため、process.env を参照するコードが実行時に落ちる。
Vite では import.meta.env を使うか、define で process.env を置き換える。
公開: 更新:
要約
Uncaught ReferenceError: process is not defined は、Node.js のグローバル変数 process をブラウザで参照したときに出ます。process は Node のランタイムが提供するもので、ブラウザには存在しません。
Vite はバンドル時に Node の process.env を自動でブラウザ用に置き換えたりしないため、環境変数は Vite の流儀である import.meta.env から読みます。
自分のコードは import.meta.env に直し、ライブラリ都合でどうしても process が必要なときは define で補います。
Uncaught ReferenceError: process is not defined実行例
process.env.VITE_API_URL はバンドル後もそのまま残り、ブラウザに近い実行環境では ReferenceError: process is not defined で終了コード 1 になる。import.meta.env に書き換えても define で置き換えても、バンドルには文字列 "https://api.example.com" が埋め込まれて終了コード 0 になる。
$ npx vite build
vite v6.4.3 building for production...
transforming...
✓ 1 modules transformed.
rendering chunks...
computing gzip size...
dist/app.iife.js 0.11 kB │ gzip: 0.12 kB
✓ built in 27ms$ grep -n 'process.env' dist/app.iife.js
3: const url = process.env.VITE_API_URL;$ node run-in-browserlike.mjs
evalmachine.<anonymous>:3
const url = process.env.VITE_API_URL;
^
ReferenceError: process is not defined
at evalmachine.<anonymous>:3:15
at evalmachine.<anonymous>:5:3
at Script.runInContext (node:vm:149:12)
at Object.runInContext (node:vm:301:6)
at file:///tmp/tmp.GUn486Btwy/run-in-browserlike.mjs:8:4
at ModuleJob.run (node:internal/modules/esm/module_job:325:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:606:24)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5)
Node.js v20.20.2
$ echo $?
1$ npx vite build
vite v6.4.3 building for production...
transforming...
✓ 1 modules transformed.
rendering chunks...
computing gzip size...
dist/app.iife.js 0.11 kB │ gzip: 0.12 kB
✓ built in 24ms$ node run-in-browserlike.mjs
API_URL = https://api.example.com
$ echo $?
0$ npx vite build
vite v6.4.3 building for production...
transforming...
✓ 1 modules transformed.
rendering chunks...
computing gzip size...
dist/app.iife.js 0.11 kB │ gzip: 0.12 kB
✓ built in 25ms$ grep -n 'api.example.com' dist/app.iife.js
3: const url = "https://api.example.com";$ node run-in-browserlike.mjs
API_URL = https://api.example.com
$ echo $?
0— 2026-09-18 時点の出力
検証環境
- 検証日
- 実行環境
node:20Debian GNU/Linux 12 (bookworm)- バージョン
- Node.js 20.20.2
- npm 10.8.2
- Python 3.11.2
- Git 2.39.5
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
- 自前コードの
process.env: Node の感覚でprocess.env.FOOを書いている。 - 依存ライブラリ: ライブラリが内部で
process.env.NODE_ENVを読んでおり、それがブラウザに混ざっている。 - CRA からの移行:
process.env.REACT_APP_*の参照が移行後も残っている。 - プレフィックス違い: Vite は
VITE_で始まる変数だけをクライアントに露出するため、それ以外はimport.meta.envに現れない。
解決策
1. import.meta.env に書き換える
自分のコードでは process.env をやめ、import.meta.env を使います。
クライアントへ露出させる変数名は VITE_ で始める必要があります。
// const url = process.env.API_URL →
const url = import.meta.env.VITE_API_URL;.env ファイル側も合わせます。
VITE_API_URL=https://api.example.comなお VITE_ を付けた変数はバンドルに含まれてブラウザから見えるため、API キーなどの秘匿情報は入れないでください。
2. ライブラリ都合の process.env を define で補う
自分では直せないライブラリが process.env を読む場合は、vite.config の define でビルド時に値を埋め込みます。define は文字列を「そのままコードに置換」するので、値は JSON.stringify で囲みます。
// vite.config.ts
export default defineConfig({
define: {
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
// 参照だけ通したい最低限のフォールバック
"process.env": {},
},
});