Vite で process is not defined になる原因と直し方【Uncaught ReferenceError・React/CRA移行】
公開日:2026-04-20/カテゴリ:Vite・React・フロントエンド/AnchorUp 技術ブログ
Vite に移行したら “process is not defined” が出た
Create React App(CRA)から Vite に移行した際、必ずといっていいほど遭遇するエラーが次です。
Uncaught ReferenceError: process is not defined
CRA では Webpack が process.env.REACT_APP_* をビルド時に文字列へ置換していました(Webpack 4 時代は process 自体も自動ポリフィル)。しかし Vite はブラウザネイティブな ESM をベースにしているため、Node.js のグローバル変数を自動注入しません。
この記事では、原因のパターンを5つに分類して、それぞれの対処法を解説します。
結論: Vite で process is not defined が出たらどう直す?
原因は「ブラウザには Node.js の process グローバルが存在しない」ことです。Vite は Webpack 4 のように process を自動でポリフィルしません。どのコードが process を参照しているかで直し方が決まります。
| エラーを出しているコード | 直し方 |
|---|---|
自分のコードの process.env.REACT_APP_XXX |
import.meta.env.VITE_XXX に置換し、.env のキーも VITE_ に変更 |
自分のコードの process.env.NODE_ENV |
Vite が自動置換するので通常は動く。import.meta.env.MODE / DEV / PROD への置換を推奨 |
ライブラリ内の process.env.XXX |
vite.config.ts の define で該当キーだけ定義 |
ライブラリ内の process.browser / process.nextTick など |
define で個別定義、または vite-plugin-node-polyfills |
vite.config.ts 内で .env が読めない |
loadEnv() を使う(後述) |
最小の修正例はこれです。
// NG: ブラウザで実行すると Uncaught ReferenceError: process is not defined
const apiUrl = process.env.REACT_APP_API_URL
// OK: Vite がビルド時に文字列へ置換する
const apiUrl = import.meta.env.VITE_API_URL
なぜブラウザで process is not defined になるのか?(Webpack 4・CRA との違い)
process は Node.js のグローバルオブジェクトで、ブラウザの JavaScript には最初から存在しません。 CRA や Webpack 4 時代のプロジェクトで動いていたのは、バンドラーが裏で肩代わりしていたからです。
| 環境 | process.env.XXX の扱い |
process オブジェクト自体 |
|---|---|---|
| Webpack 4(CRA 3 系まで) | DefinePlugin でビルド時に置換 | node.process で自動ポリフィル |
| Webpack 5(CRA 5 / react-scripts 5) | DefinePlugin でビルド時に置換 | 自動ポリフィル廃止 |
| Vite | import.meta.env.* のみ公式サポート |
ポリフィルなし |
つまり「CRA では動いていたのに Vite で落ちる」のは、コードが壊れたのではなく、CRA が process.env.REACT_APP_* を文字列に置換してくれていた仕組みが Vite には無いためです。Vite はこれを import.meta.env という ESM 標準の仕組みで置き換えています。
なお Create React App は 2025年2月に React チームから新規プロジェクトでの非推奨(sunset)が発表されており、Vite への移行で本エラーに遭遇するケースは今後も増える見込みです。
Vite は process.env.NODE_ENV だけは自動で置換する
ここは誤解が多いポイントです。現行の Vite(v8 のソースで確認)は、ライブラリモード以外では process.env.NODE_ENV を自動でモード名の文字列に置換します。React 本体が内部で process.env.NODE_ENV を参照していても react process is not defined にならないのはこのためです。
そのため、React を使っていて process is not defined が出る場合、犯人は React 本体ではなく、自前コードか別のライブラリです。
Uncaught ReferenceError: process is not defined の出どころを特定するには?
ブラウザの DevTools でエラー行のファイル名を見るのが最短です。 スタックトレースのファイルが src/ 配下なら自前コード、node_modules/.vite/deps/ 配下ならライブラリ由来です。
Uncaught ReferenceError: process is not defined
自前コードの参照はこれで一覧できます。
grep -rn "process\." src/
ライブラリ由来の場合は、該当パッケージを特定してから以下の原因2・3の対処に進みます。
原因1: 自前コードで process.env.XXX を使っている(CRA→Vite 移行の定番)
最も多いケースです。CRA では process.env.REACT_APP_XXX で環境変数を参照しますが、Vite では import.meta.env.VITE_XXX に変更する必要があります。
環境変数のプレフィックスも REACT_APP_ から VITE_ に変わります。
修正前(CRA):
const apiUrl = process.env.REACT_APP_API_URL
const isDev = process.env.NODE_ENV === 'development'
修正後(Vite):
const apiUrl = import.meta.env.VITE_API_URL
const isDev = import.meta.env.DEV // boolean として提供される
// または
const isDev = import.meta.env.MODE === 'development'
.env ファイルのキー名も変更が必要です:
# .env(変更前)
REACT_APP_API_URL=https://api.example.com
# .env(変更後)
VITE_API_URL=https://api.example.com
一度に全部書き換えられない場合は、Vite の envPrefix で REACT_APP_ も公開対象にできます。ただし参照側は import.meta.env.REACT_APP_XXX に変える必要がある点は同じです(process.env のままでは動きません)。
// vite.config.ts(段階的移行用)
export default defineConfig({
envPrefix: ['VITE_', 'REACT_APP_'],
})
注意:
envPrefixに指定したプレフィックスの変数はすべてクライアントのバンドルに埋め込まれます。秘密情報を持つ変数にこのプレフィックスを付けないでください。
まず自前コードの process.env を全て洗い出すには次のコマンドが便利です:
grep -rn "process\.env" src/
原因2: サードパーティライブラリが process.env を参照している
ライブラリが process.env.NODE_ENV 以外のキーを参照している場合、vite.config.ts の define でそのキーだけを定義します。 自前コードを直しても同じエラーが出続けるなら、このパターンです。
前述のとおり process.env.NODE_ENV は Vite が自動置換するので通常は定義不要です。問題になるのは process.env.DEBUG や process.env.SOME_LIB_FLAG のようなライブラリ固有のキーです。
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
define: {
// ライブラリが参照するキーだけを個別に定義する
'process.env.DEBUG': JSON.stringify(false),
// ライブラリモード等で NODE_ENV を明示したい場合
'process.env.NODE_ENV': JSON.stringify('production'),
},
})
define の値は「コードとしてそのまま埋め込まれる文字列」です。文字列を渡したいときは必ず JSON.stringify() で包みます('production' をそのまま書くと production という変数名として埋め込まれ、今度は production is not defined になります)。
注意:
'process.env': process.envのように Node.js のprocess.envをそのまま渡すと、サーバー側のシークレットがビルド成果物に含まれるリスクがあります。必要なキーだけを個別に定義するのが安全です。
原因3: process オブジェクト自体を参照している
ライブラリによっては process.env ではなく process オブジェクト全体を参照しているものがあります。process.browser や process.version を使うケースが該当します。
// vite.config.ts
export default defineConfig({
define: {
'process.env': '{}',
'process.browser': 'true',
'process.version': JSON.stringify(process.version),
},
})
広範なポリフィルが必要な場合は vite-plugin-node-polyfills が便利です:
npm install -D vite-plugin-node-polyfills
// vite.config.ts
import { defineConfig } from 'vite'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
export default defineConfig({
plugins: [
nodePolyfills({
include: ['process', 'buffer'],
}),
],
})
原因4: 開発環境と本番ビルドで挙動が違う(dev ではエラー・build では undefined)
Vite は dev サーバーと本番ビルドで process.env の扱いが異なります。 現行の Vite のソース(packages/vite/src/node/plugins/define.ts)では、ライブラリモード以外のビルド時に process.env を {}、process.env.NODE_ENV をモード名に置換しています。一方 dev サーバーでは process.env.NODE_ENV 以外は置換されません。
| コード | npm run dev |
npm run build 後 |
|---|---|---|
process.env.NODE_ENV |
置換される(動く) | 置換される(動く) |
process.env.REACT_APP_API_URL |
process is not defined | エラーは出ず undefined |
process.browser / process.version |
process is not defined | process is not defined |
このため「dev では落ちるのに本番は画面が出る(ただし API の URL が undefined で通信に失敗する)」という分かりにくい症状になります。本番で値が undefined になっている場合も原因は同じで、import.meta.env.VITE_XXX への置換が正解です。
確認方法: vite preview コマンドで本番ビルドをローカル再現できます。
npm run build && npx vite preview
npm run dev で確認するだけでは気づけない問題を事前に検出できます。デプロイ先で環境変数が undefined になる問題は Vercel で環境変数が undefined になる時の原因と対策 も参照してください。
vite.config.ts の中で process.env.VITE_XXX が undefined になる場合
vite.config.ts の実行時点では .env ファイルはまだ process.env に読み込まれていません。 設定ファイル内で .env の値を使いたい場合は loadEnv() を使います。
// vite.config.ts
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => {
// 第3引数 '' で VITE_ 以外の変数も読み込む(設定ファイル内でのみ使う)
const env = loadEnv(mode, process.cwd(), '')
return {
define: {
__API_URL__: JSON.stringify(env.API_URL),
},
}
})
原因5: TypeScript の型エラーとして現れる場合
実行時エラーではなく、ビルド前の型チェックで process が型エラーになることもあります。
Cannot find name 'process'. Do you need to install type definitions for node?
この場合は @types/node のインストールと tsconfig.json の設定が必要です:
npm install -D @types/node
{
"compilerOptions": {
"types": ["node", "vite/client"]
}
}
vite/client を追加することで import.meta.env の型補完も正しく効くようになります。
移行チェックリスト
エラーが出た場合は次の順番で確認してください:
-
自前コードの
process.env.XXXを全てimport.meta.env.VITE_XXXに置換したかgrep -rn "process\.env" src/ -
.envファイルのキー名をVITE_プレフィックスに変更したか -
vite.config.tsのdefineにライブラリ向けのprocess.envを追加したか -
npm run build && npx vite previewで本番環境を再現して確認したか -
TypeScript 型エラーなら
@types/node+tsconfig.jsonのtypes設定をしたか
まとめ
| 原因 | 対処法 |
|---|---|
自前コードで process.env を使用 |
import.meta.env.VITE_XXX に置換 |
ライブラリが process.env を参照 |
vite.config.ts の define に追加 |
process オブジェクト自体が必要 |
vite-plugin-node-polyfills を使用 |
dev ではエラー・本番では undefined |
import.meta.env.VITE_XXX に置換 + vite preview で確認 |
vite.config.ts で .env が読めない |
loadEnv(mode, process.cwd(), '') を使う |
| TypeScript 型エラー | @types/node + tsconfig.json の types 設定 |
CRA から Vite への移行は開発体験・ビルド速度の大幅な向上が見込めます。しかし process.env の扱いの違いがつまずきポイントになりがちです。上記のチェックリストを順番に確認すれば、ほとんどのケースで解決できます。
Vite のバージョンアップ自体で別のエラーが出ている場合は Vite 6 移行で動かない時の原因と対策 も合わせて確認してください。