T-CREATOR

Electron トラブルシュート:白画面(White Screen)問題を 3 分で切り分け

Electron トラブルシュート:白画面(White Screen)問題を 3 分で切り分け

Electron アプリを開発していて、突然真っ白な画面が表示された経験はありませんか。一瞬で心配になり、「何が原因なのか」「どこから調べればいいのか」と困惑してしまいますよね。

この白画面問題は Electron 開発でよく遭遇するトラブルの一つです。しかし、適切な手順で診断すれば、わずか 3 分で原因を特定できます。今回は、原因別のアプローチで効率的に問題を切り分ける方法をご紹介しましょう。

背景

Electron アプリケーションにおける白画面問題は、様々な場面で発生します。開発中にコードを変更した直後、ビルド後の実行時、または本番環境へのデプロイ後など、タイミングは多岐にわたります。

mermaidflowchart TD
    start[Electron アプリ起動] --> main[メインプロセス開始]
    main --> window[BrowserWindow 作成]
    window --> load[HTML ファイル読み込み]
    load --> render[レンダラープロセス開始]
    render --> display[画面表示]

    main -->|エラー| error1[メインプロセス エラー]
    load -->|失敗| error2[リソース読み込み エラー]
    render -->|クラッシュ| error3[レンダラープロセス エラー]

    error1 --> white[白画面表示]
    error2 --> white
    error3 --> white

上図が示すように、Electron の起動フローは複数のステップから構成されており、各段階でエラーが発生する可能性があります。

開発者が直面する典型的なシナリオとしては、以下のようなケースが挙げられます。

  • 新しい機能を追加した後の初回起動時
  • 依存関係を更新した後の動作確認時
  • パッケージングした実行ファイルの動作テスト時
  • 異なる環境での動作確認時

これらの状況では、エラーメッセージが表示されずに単純な白画面になってしまうことが多く、原因の特定が困難になります。

課題

Electron の白画面問題における最大の課題は、原因の特定に時間がかかることです。従来のウェブ開発とは異なり、Electron では以下の要因が問題を複雑化させます。

複数プロセスによる複雑性

Electron はメインプロセスとレンダラープロセスの 2 つのプロセスで動作します。どちらのプロセスで問題が発生しているかを判断するだけでも、相当な時間を要する場合があります。

エラー情報の不足

白画面の状態では、通常のエラーメッセージやスタックトレースが表示されません。そのため、ログファイルや開発者ツールを駆使して情報を収集する必要があります。

環境依存の問題

開発環境では正常に動作していたアプリが、本番環境やパッケージング後に白画面になるケースも少なくありません。環境の違いによる影響を特定するには、系統的なアプローチが必要です。

これらの課題を解決するために、効率的な診断手順を確立することが重要になります。

解決策

白画面問題を 3 分で切り分けるためには、発生頻度の高い原因から順番にチェックしていく戦略的なアプローチが有効です。以下の 3 つの主要原因に分けて、具体的な診断方法をご説明します。

原因 1:レンダラープロセスのクラッシュ

レンダラープロセスのクラッシュは、白画面問題の最も一般的な原因の一つです。JavaScript のエラーや DOM 操作の問題が主な要因となります。

DevTools での確認方法

まず、DevTools を開いて Console タブを確認しましょう。

javascript// メインプロセス側で DevTools を開く設定
const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nodeIntegration: true,
    contextIsolation: false,
    // 開発時は DevTools を自動で開く
    devTools: true,
  },
});

// DevTools を手動で開く
mainWindow.webContents.openDevTools();

DevTools が開いたら、以下の手順で確認を進めます。

javascript// Console タブで確認すべきエラーの例
// 1. JavaScript の実行エラー
Uncaught TypeError: Cannot read property 'name' of undefined

// 2. モジュール読み込みエラー
Uncaught Error: Cannot resolve module './component.js'

// 3. DOM 操作エラー
Uncaught DOMException: Failed to execute 'appendChild' on 'Node'

Console タブでエラーが確認できた場合は、該当するコードを修正することで問題を解決できます。

プロセス監視ツールの活用

DevTools でエラーが見つからない場合は、プロセス監視ツールを使用してレンダラープロセスの状態を確認します。

javascript// メインプロセスでレンダラープロセスの状態を監視
mainWindow.webContents.on('crashed', (event, killed) => {
  console.log('レンダラープロセスがクラッシュしました');
  console.log('強制終了:', killed);

  // クラッシュ時の復旧処理
  mainWindow.reload();
});

// プロセスの応答状況を確認
mainWindow.webContents.on('unresponsive', () => {
  console.log('レンダラープロセスが応答していません');
});

mainWindow.webContents.on('responsive', () => {
  console.log('レンダラープロセスが応答を再開しました');
});

これらのイベントリスナーを設定することで、レンダラープロセスの異常を検出できます。

原因 2:メインプロセスの初期化エラー

メインプロセスの初期化でエラーが発生すると、BrowserWindow 自体が正常に作成されず、結果として白画面が表示されます。

ログ出力の確認

メインプロセスのログは、通常のコンソール出力として確認できます。

javascript// メインプロセスでのエラーハンドリング
process.on('uncaughtException', (error) => {
  console.error(
    'メインプロセスで捕捉されない例外が発生しました:',
    error
  );
  // ログファイルに出力
  const fs = require('fs');
  const path = require('path');

  const logPath = path.join(__dirname, 'error.log');
  fs.appendFileSync(
    logPath,
    `${new Date().toISOString()}: ${error.stack}\n`
  );
});

// Promise の reject をキャッチ
process.on('unhandledRejection', (reason, promise) => {
  console.error('未処理の Promise rejection:', reason);
});

起動シーケンスの検証

Electron の起動シーケンスを段階的に確認し、どの時点でエラーが発生しているかを特定します。

javascript// 起動シーケンスのデバッグログ
const { app, BrowserWindow } = require('electron');

console.log('1. アプリケーション初期化開始');

app.whenReady().then(() => {
  console.log('2. アプリケーション準備完了');

  try {
    console.log('3. BrowserWindow 作成開始');
    const mainWindow = new BrowserWindow({
      width: 800,
      height: 600,
      webPreferences: {
        nodeIntegration: true,
        contextIsolation: false,
      },
    });

    console.log('4. BrowserWindow 作成完了');

    console.log('5. ファイル読み込み開始');
    mainWindow
      .loadFile('index.html')
      .then(() => {
        console.log('6. ファイル読み込み完了');
      })
      .catch((error) => {
        console.error('ファイル読み込みエラー:', error);
      });
  } catch (error) {
    console.error('BrowserWindow 作成エラー:', error);
  }
});

このようなログ出力により、初期化のどの段階で問題が発生しているかを特定できます。

原因 3:リソース読み込み失敗

HTML、CSS、JavaScript ファイルなどのリソース読み込みに失敗すると、白画面が表示される場合があります。

ファイルパスの検証

最も一般的な原因は、ファイルパスの間違いです。特に相対パスと絶対パスの使い分けに注意が必要です。

javascript// 正しいファイルパス指定の例
const path = require('path');

// HTML ファイルの読み込み
mainWindow.loadFile(path.join(__dirname, 'src', 'index.html'));

// 画像リソースの読み込み(HTML 内)
// 相対パス(推奨)
<img src="./assets/images/logo.png" alt="ロゴ">

// 絶対パス(避けるべき)
<img src="/Users/username/project/assets/images/logo.png" alt="ロゴ">

ファイルの存在確認も重要なチェック項目です。

javascript// ファイル存在確認のユーティリティ
const fs = require('fs');

function checkFileExists(filePath) {
  try {
    fs.accessSync(filePath, fs.constants.F_OK);
    console.log(`ファイルが存在します: ${filePath}`);
    return true;
  } catch (error) {
    console.error(`ファイルが存在しません: ${filePath}`);
    return false;
  }
}

// メインファイルの確認
const indexPath = path.join(__dirname, 'src', 'index.html');
if (checkFileExists(indexPath)) {
  mainWindow.loadFile(indexPath);
} else {
  console.error('index.html が見つかりません');
}

CORS エラーの確認

Electron アプリでは、ローカルファイルからの読み込みで CORS エラーが発生する場合があります。

javascript// CORS エラーを回避する設定
const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nodeIntegration: true,
    contextIsolation: false,
    // ローカルファイルの制限を緩和
    allowRunningInsecureContent: true,
    webSecurity: false, // 開発時のみ使用
  },
});

Network タブでリソースの読み込み状況を確認することも重要です。

javascript// リソース読み込みの監視
mainWindow.webContents.on(
  'did-fail-load',
  (event, errorCode, errorDescription, validatedURL) => {
    console.error('リソース読み込み失敗:', {
      errorCode,
      errorDescription,
      url: validatedURL,
    });
  }
);

// リソース読み込み完了の確認
mainWindow.webContents.on('did-finish-load', () => {
  console.log('すべてのリソースの読み込みが完了しました');
});

具体例

実際の開発現場で遭遇する具体的なケースとその対処法をご紹介します。これらの例を参考に、自分のプロジェクトでの問題解決に活用してください。

ケース 1:JavaScript モジュール読み込みエラー

症状: アプリ起動時に白画面が表示され、Console に以下のエラーが出力される

javascript// エラーログ例
Uncaught Error: Cannot resolve module './components/Header.js'
    at Module.require (webpack-internal:///./src/main.js:15:23)
    at Object.<anonymous> (webpack-internal:///./src/main.js:3:18)

原因: ファイルパスの間違いまたはファイルの不存在

解決手順:

  1. エラーで指摘されたファイルパスを確認
  2. 実際のファイル構造と照らし合わせ
  3. 正しいパスに修正
javascript// 修正前(エラーの原因)
import Header from './components/Header.js'; // ファイルが存在しない

// 修正後
import Header from './components/HeaderComponent.js'; // 正しいファイル名

ケース 2:CSS 読み込み失敗による部分白画面

症状: HTML の構造は表示されるが、スタイルが適用されず白っぽい画面になる

html<!-- 問題のある CSS 読み込み -->
<link rel="stylesheet" href="/styles/main.css" />

エラーログ例:

perlGET file:///styles/main.css net::ERR_FILE_NOT_FOUND

解決手順:

  1. Network タブで CSS ファイルの読み込み状況を確認
  2. ファイルパスを相対パスに変更
  3. ファイルの存在確認
html<!-- 修正後 -->
<link rel="stylesheet" href="./assets/css/main.css" />

ケース 3:非同期処理の競合による白画面

症状: アプリは起動するが、データ読み込み後に白画面になる

javascript// 問題のあるコード例
async function loadUserData() {
  const userData = await fetchUserFromAPI();
  document.getElementById('user-info').innerHTML =
    userData.name; // エラーの原因
}

// fetchUserFromAPI() が失敗した場合、userData が undefined になり
// userData.name でエラーが発生

エラーログ例:

javascriptUncaught TypeError: Cannot read property 'name' of undefined
    at loadUserData (main.js:45:67)

解決手順:

  1. 非同期処理にエラーハンドリングを追加
  2. データの存在確認を実装
  3. フォールバック処理を設定
javascript// 修正後のコード
async function loadUserData() {
  try {
    const userData = await fetchUserFromAPI();

    // データの存在確認
    if (userData && userData.name) {
      document.getElementById('user-info').innerHTML =
        userData.name;
    } else {
      document.getElementById('user-info').innerHTML =
        'ユーザー情報を取得できませんでした';
    }
  } catch (error) {
    console.error('ユーザーデータ読み込みエラー:', error);
    document.getElementById('user-info').innerHTML =
      'エラーが発生しました';
  }
}

ケース 4:パッケージング後の白画面

症状: 開発環境では正常に動作するが、パッケージング後に白画面になる

主な原因:

javascript// 開発時は動作するが、パッケージング後にエラーになるコード例
const fs = require('fs');
const path = require('path');

// 開発時のパス(動作する)
const configPath = path.join(__dirname, 'config.json');

// パッケージング後は __dirname の場所が変わるため、ファイルが見つからない

解決手順:

  1. パッケージング後のディレクトリ構造を確認
  2. リソースファイルの配置場所を修正
  3. アプリケーションリソースパスを使用
javascript// 修正後のコード
const { app } = require('electron');

// パッケージング後も動作するパス指定
const configPath = path.join(
  app.getAppPath(),
  'config.json'
);

// または、ユーザーデータディレクトリを使用
const userDataPath = app.getPath('userData');
const configPath = path.join(userDataPath, 'config.json');

これらの具体例を参考に、段階的に問題を切り分けることで、効率的に白画面問題を解決できます。

まとめ

Electron の白画面問題を 3 分で切り分けるための手順をまとめました。以下のチェックリストを活用して、迅速な問題解決を図ってください。

3 分切り分けチェックリスト

時間チェック項目確認方法対処法
1 分目DevTools Console 確認Ctrl+Shift+I で Console タブエラーメッセージに従ってコード修正
1 分目ファイル存在確認fs.accessSync() または手動確認正しいパスに修正、ファイル作成
2 分目メインプロセスログ確認ターミナル/コマンドプロンプト初期化エラーを修正
2 分目レンダラープロセス監視crashedイベントリスナー設定プロセス再起動、エラー原因特定
3 分目Network タブ確認DevTools の Network タブリソースパス修正、CORS 設定調整
3 分目環境差異確認開発環境とパッケージング後比較パス指定方法の見直し

予防策の提案

今後の白画面問題を予防するために、以下の開発手法を取り入れることをお勧めします。

1. エラーハンドリングの充実

javascript// 包括的なエラーハンドリングの実装
function setupErrorHandling() {
  // メインプロセスのエラー
  process.on('uncaughtException', handleMainProcessError);
  process.on(
    'unhandledRejection',
    handleUnhandledRejection
  );

  // レンダラープロセスのエラー
  window.addEventListener('error', handleRendererError);
  window.addEventListener(
    'unhandledrejection',
    handlePromiseRejection
  );
}

2. ログ機能の強化

javascript// ログレベル別の出力機能
const logger = {
  debug: (message) => console.log(`[DEBUG] ${message}`),
  info: (message) => console.info(`[INFO] ${message}`),
  warn: (message) => console.warn(`[WARN] ${message}`),
  error: (message) => console.error(`[ERROR] ${message}`),
};

3. 開発時の自動チェック機能

javascript// 開発時の自動診断機能
function performStartupDiagnostics() {
  const requiredFiles = [
    './src/index.html',
    './src/main.js',
    './assets/css/main.css',
  ];

  requiredFiles.forEach((file) => {
    if (!fs.existsSync(file)) {
      logger.error(`必須ファイルが見つかりません: ${file}`);
    }
  });
}

適切な診断手順と予防策を組み合わせることで、Electron 開発における白画面問題を効率的に解決し、開発生産性を向上させることができます。問題が発生した際は、このガイドを参考に段階的なアプローチで原因を特定してください。

関連リンク