Webアプリの真っ白な画面を直す方法
真っ白な画面は、ほぼ必ず次のどちらかを意味します。アプリのJavaScriptが何かを描画する前にクラッシュしたか、JavaScriptがそもそも読み込まれなかったかです。ブラウザのコンソールを開き(右クリック → 検証 → コンソール)、最初に出ている赤いエラーを読みましょう。そのあとネットワークタブで、読み込みに失敗したファイルを確認します。多くの原因は、環境変数の不足、ベースパスの誤り、ビルドが終わっていないこと、そして1つのコンポーネントでのクラッシュです。
このガイドでは、ReactやVueなどのフレームワークで作られたシングルページアプリ(AIビルダーで作られたアプリを含む)を扱います。真っ白な画面が最も起きやすいのがこの種のアプリです。
画面が白くなる理由
最近のシングルページアプリ(SPA)は、ブラウザにほぼ空のHTMLファイルを送ります。おおよそ次のようなものです。
<body>
<div id="root"></div>
<script type="module" src="/assets/index-a1b2c3.js"></script>
</body>
その後、JavaScriptがその空のdivの中にページ全体を組み立てます。スクリプトが読み込めなかったり、描画の前にエラーを投げたりすると、divは空のままになり、白い画面が見えます。ページが目に見える形で「壊れている」わけではなく、単に何も描画されなかっただけです。
だからこそ、修正は常にページ自体ではなく、開発者ツールから始まります。
ステップ1:コンソールを読む
開発者ツールを開きましょう。ページを右クリックして検証を選ぶか、F12キー(Macでは Cmd+Option+I)を押します。コンソールタブに移動して、ページを再読み込みしてください。
最初の赤いエラーを見ましょう。後のエラーは、多くの場合ほかの問題の副作用です。そのエラーが原因を示しています。
| コンソールのメッセージ(典型的な文言) | 意味 | 参照先 |
|---|---|---|
Cannot read properties of undefined (reading '...') | 存在するはずのデータがなかった | ステップ4 |
... is not defined / ... is not a function | インポート、変数、設定のいずれかが不足している | ステップ4またはステップ3 |
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html" | スクリプトのURLがJavaScriptではなくHTMLのページを返した | ステップ2 |
Uncaught SyntaxError: Unexpected token '<' | 同じ原因で、JavaScriptを期待した場所にHTMLが来た | ステップ2 |
supabaseUrl is required、Missing API keyなど | 環境変数が空である | ステップ3 |
Access to fetch ... has been blocked by CORS policy | 別のドメインへのリクエストがブロックされた | CORSエラーの直し方をご覧ください |
| エラーがまったくない | 描画は行われたが何も表示されない、またはCSSで隠れている | ステップ6 |
ファイル名と行番号を含め、エラーの全文をコピーしてください。AIビルダーを使っているなら、そのままチャットに貼り付けましょう。
ステップ2:ファイルが読み込まれたかを確認する
ネットワークタブを開き、キャッシュを無効にするにチェックを入れて、再読み込みします。.jsと.cssファイルへのリクエストを見ましょう。
- JavaScriptファイルでステータス404:ページが、サーバーに存在しないファイルを要求しています。
- ステータス200だが種類が
text/html:サーバーが、スクリプトの代わりにページを返しました(多くはSPAのフォールバックによるindex.htmlそのものです)。根本原因は同じで、ファイルがページの期待する場所にありません。
よくある理由は次のとおりです。
ベースパスの誤り。 アプリがexample.com/app/のようなサブフォルダで配信されているのに、/assets/...からファイルを読み込むようにビルドされていると、すべてのスクリプトのリクエストが外れます。Viteではvite.configのbaseオプション、Create React Appではhomepageフィールド、Next.jsではbasePathです。アプリが実際に配信される場所と一致させる必要があります。
古いindex.html。 ビルドツールは、index-a1b2c3.jsのようにコンテンツのハッシュを付けたファイル名を付けます。新しいデプロイの後、古いファイルは消えています。ブラウザやCDNがまだ古いindex.htmlをキャッシュしていると、古いファイルを要求し、何も得られません。強制再読み込み(Cmd+Shift+RまたはCtrl+Shift+R)で確認できます。根本的な解決策は、ハッシュ付きのファイルは長期間キャッシュし、index.htmlは短い時間か、キャッシュなしのヘッダーで配信することです。
ビルドが終わっていない、またはデプロイされていない。 ビルドが失敗していると、ホストは古いか空の出力フォルダを配信しているかもしれません。ビルドのログでエラーを確認してください。
間違ったフォルダが公開されている。 ホストは、プロジェクトのソースフォルダではなく、ビルドの出力(通常はdistやbuild)を配信しなければなりません。ソースを配信すると、/src/main.tsxを指すindex.htmlが返り、ブラウザはそれを実行できません。
ステップ3:環境変数を確認する
フロントエンドのアプリは、APIのURLや公開キーのような設定を、ビルド時に読み込むことがよくあります。本番のビルドで変数が不足していると、たとえばcreateClient(undefined, undefined)のようなコードは即座に例外を投げ、ページは白くなります。
知っておくべきことは次のとおりです。
- Viteでは、ブラウザのコードで使えるのは
VITE_で始まる変数だけで、import.meta.env.VITE_NAMEとして読みます。Create React AppではREACT_APP_、Next.jsではNEXT_PUBLIC_です。 - これらの値はアプリのビルド時に埋め込まれます。ビルドの後で変数を追加しても、再ビルドして再デプロイするまでは何も起きません。
- プレビューやローカルのマシンには、本番のビルドにはない
.envファイルがあるかもしれません。同じ変数をホストにも設定してください。 - これらの接頭辞が付いたものは、すべて公開のJavaScriptに含まれます。公開してよい値だけを置き、秘密のキーは絶対に置かないでください。
簡単なテストとして、コンソールのエラーの中で設定名の近くにあるundefinedを探すか、次のように頼みましょう。
公開されたアプリが真っ白な画面を表示しています。フロントエンドが読み込むすべての環境変数を一覧にし、本番のビルドでどれが不足していたり空だったりするかを確認してください。また、変数が不足しているときは、真っ白な画面ではなく、分かりやすいエラーメッセージを表示するようアプリを修正してください。
ステップ4:クラッシュを直す
コンソールに通常のJavaScriptのエラーが出ている場合、描画の途中でコードがクラッシュしています。AIで作ったアプリでよくある原因は次のとおりです。
- データがまだ読み込まれていない。
userが届く前に、コンポーネントがuser.nameを読んでいる。直し方は、読み込み中の状態を作るか、オプショナルチェーン(user?.name)を使うことです。 - データが空である。 新しいアカウントにはレコードがなく、コードはリストに少なくとも1件あると想定している。
- 予期しないデータの形。 コードが期待したリストの代わりに、APIがエラーのオブジェクトを返した。
- インポートの欠落。 ファイルの名前を変えたり移動したりした後。
- サーバーサイドの描画中に、ブラウザ専用のAPIを使っている。 Next.jsのサーバーコンポーネントで
windowやlocalStorageを使うなど。
AIには、完全なエラーと、ページと、どのアカウントでログインしていたかを伝えましょう。
ダッシュボードのページが新規利用者では真っ白です。コンソールには
TypeError: Cannot read properties of undefined (reading 'map')がProjectList.tsx:18で出ています。プロジェクトを持つ私のアカウントでは動作します。空のアカウントでは「まだプロジェクトはありません」と表示されるよう修正し、プレビューで新しいアカウントを確認してください。
ステップ5:エラーバウンダリーを追加する
Reactでは、1つのコンポーネントがクラッシュするとアプリ全体がアンマウントされることがあり、だから小さなバグで完全に真っ白なページになります。エラーバウンダリーは、その下で起きた描画エラーを捕まえて、代わりにフォールバックを表示するコンポーネントです。
主要なルートの周りにエラーバウンダリーを追加し、「問題が発生しました」と再読み込みボタンを表示して、エラーをコンソールに記録してください。ヘッダーとナビゲーションはその外に置き、描画され続けるようにしてください。
これでバグが直るわけではありませんが、訪問者は白い画面ではなくメッセージを見ることになり、あなたは壊れた場所を知ることができます。
ステップ6:エラーはないのに白いまま
コンソールにエラーがなく、スクリプトも読み込まれている場合は、次を確認しましょう。
- Elementsタブを確認する。
<div id="root">の中に内容がありますか? あるなら描画はされていますが、見えていません。白い文字が白い背景にある、opacity: 0、display: none、または全画面の要素がそれを覆っている、などが考えられます。 - ルーターを確認する。 現在のURLに一致するルートがなく、「見つかりません」のルートもない場合、ルーターによっては何も描画しません。404ページを表示するキャッチオールのルートを追加しましょう。
- マウント先を確認する。 コードは、存在する要素にマウントしなければなりません。
index.htmlにid="app"があるのに、コードがrootを探していると、何も表示されません(そしてReactは通常エラーを記録します)。 - ブラウザの拡張機能を確認する。 プライベートウィンドウで試してください。広告ブロッカーが、
analyticsやadsのような名前のスクリプトを時々ブロックします。
特定のページを再読み込みしたときだけ白くなる?
トップページは動くのに、/dashboardを再読み込みすると白いページや404になる場合、サーバーはアプリのルートに対してindex.htmlを返す方法を知りません。これはルーティングのフォールバックの問題で、デプロイ後の404エラーの直し方で扱っています。
よくある間違い
- 最後のエラーを読んで、最初のエラーを読まない。 最初の赤い行が通常は原因です。
- 再ビルドせずに環境変数を設定する。 フロントエンドの変数は、ビルド時に固定されます。
- 自分のアカウントだけでテストする。 空のアカウントでのクラッシュは、白い画面の最も一般的な原因の一つです。
- デプロイが成功したと思い込む。 コードをデバッグする前に、ビルドのログを確認しましょう。
- 何でもブラウザのキャッシュのせいにする。 強制再読み込みなら数秒で切り分けられます。それでも白いなら、ほかの原因です。
Mythexでの真っ白な画面
プレビューが白い場合は、まずアプリが動いているかを確認し(コード → ターミナルを開く)、それからMythexに正しいサーバーを起動するよう頼むか、プレビューのツールバーの更新をクリックするか、/fixを使いましょう。公開されたURLが白い場合、ドキュメントでは、1分ほど待って強制再読み込みすること、公開する前に環境変数とデータベースのセットアップを確認すること、ホスティングの枠を確認することを勧めています。公開されたアプリはスナップショットであることを忘れないでください。何かを直した後は、再度公開しましょう。変更が原因なら、最後の正常な返信のこの時点に戻すを使うと、プロジェクトを巻き戻せます。ドキュメントのトラブルシューティングと公開のトラブルシューティング、そして一般的なAIで作ったアプリのデバッグ方法のガイドもご覧ください。
真っ白な画面のチェックリスト
- コンソールで最初の赤いエラーを読んだ
- ネットワークタブで、404になっている、またはHTMLを返している
.js/.cssファイルを確認した - ベースパスが、アプリの配信先と一致している
- ビルドが終わっており、公開されているのはビルドの出力フォルダである
- 本番のビルドに、すべてのフロントエンドの環境変数を設定し、再ビルドした
- 空のアカウントや新規アカウントを含めて、クラッシュを直した
- 今後のクラッシュでもメッセージが出るように、エラーバウンダリーを設置した
- 不明なURLのためのキャッチオールのルートがある
- 強制再読み込みとプライベートウィンドウで、直した後に確認した
よくある質問
Reactアプリが真っ白な画面になるのはなぜですか?
通常は、何かが描画される前にJavaScriptがクラッシュしたか、JavaScriptファイルがそもそも読み込まれなかったかのどちらかです。ブラウザのコンソールを開くと、赤いエラーが原因と、そのエラーが起きたファイルと行を示しています。
ローカルでは動くのに、デプロイ後に真っ白な画面になるのはなぜですか?
最も多い原因は、本番のビルドに環境変数が設定されていないこと、JavaScriptとCSSのファイルが誤ったパスから要求されていること(ベースパスの不一致)、そして古くキャッシュされたindex.htmlが、もう存在しないファイルを指していることです。
「Failed to load module script」とはどういう意味ですか?
ブラウザがJavaScriptファイルを要求したところ、代わりにHTMLのページが返ってきたということです。通常はサイトのindex.htmlか、エラーページです。ファイルのパスが間違っているか、サーバーにファイルが存在しないため、ビルドの出力とアプリのベースパス設定を確認してください。
1つのバグでページ全体が真っ白になるのを防ぐにはどうすればよいですか?
エラーバウンダリーを追加します。Reactでは、エラーバウンダリーは、その下にあるページの部分で描画エラーを捕まえ、すべてを消す代わりにフォールバックのメッセージを表示するコンポーネントです。