JavaScript ошибка в главном процессе Electron: полное руководство

Раздел: Программирование -> Отладка ошибок в Electron/Node.js

Ошибка JavaScript в главном процессе Electron: причины и способы устранения

Сообщение JavaScript error occurred in the main process появляется, когда в главном процессе (файл main.js) возникает необработанное исключение. Это может быть синтаксическая ошибка, вызов несуществующей функции, проблема с импортом модуля или ошибка IPC. В статье представлены основные и альтернативные подходы к отладке и исправлению.

Как обработать любую ошибку в главном процессе, чтобы предотвратить вылет приложения?

Самое надёжное решение - глобальный перехват необработанных исключений с помощью process.on('uncaughtException') и оборачивание основного кода в try/catch. Это позволяет логировать ошибку и, при необходимости, корректно завершить приложение.

// main.js
const { app, BrowserWindow } = require('electron');

process.on('uncaughtException', (error) => {
  console.error('Необработанная ошибка:', error.message);
  console.error(error.stack);
  // Логирование в файл
  const fs = require('fs');
  fs.appendFileSync('error.log', `${new Date().toISOString()} ${error.stack}\n`);
  // Можно показать диалог пользователю
  const { dialog } = require('electron');
  dialog.showErrorBox('Ошибка', error.message);
  app.quit();
});

app.whenReady().then(() => {
  try {
    const win = new BrowserWindow({ width: 800, height: 600 });
    win.loadFile('index.html');
  } catch (err) {
    console.error('Ошибка при создании окна:', err);
    process.emit('uncaughtException', err);
  }
});

Javascript error occurred in the main process (ошибка javascript в главном процессе)

Проблема: После перехвата ошибки приложение может остаться в нестабильном состоянии. Рекомендуется завершить процесс или показать сообщение. Также не следует перехватывать ошибки, которые могут быть обработаны локально.

Как использовать инструменты разработчика для отладки главного процесса?

Включить отладку главного процесса можно через флаг --inspect или --remote-debugging-port. Откройте приложение с этими параметрами:

electron --inspect=5858 main.js

Затем в браузере Chrome перейдите на chrome://inspect и подключитесь к удалённому отладчику. Это даст доступ к консоли, точкам остановки и стеку вызовов главного процесса.

Проблема: Иногда отладчик не подключается из-за блокировки порта. Используйте другой порт или проверьте настройки безопасности.

Как отключить встроенный обработчик ошибок Electron, чтобы увидеть полный стек?

По умолчанию Electron показывает стандартное окно с сообщением. Для получения подробной информации добавьте в main.js:

process.on('unhandledRejection', (reason) => {
  console.error('Необработанное отклонение промиса:', reason);
});

// Также можно отключить стандартный диалог
app.on('web-contents-created', (event, contents) => {
  contents.on('console-message', (event, level, message, line, sourceId) => {
    console.log('Console message:', message);
  });
});

Проблема: Если ошибка возникает до подключения обработчика, она не будет перехвачена. Разместите код в самом начале файла.

Как исправить ошибки импорта модулей в главном процессе?

Частая причина - неправильные пути или отсутствие модуля. Проверьте пути с помощью __dirname и path.join. Используйте только require (ESM модули в главном процессе требуют дополнительной настройки). Пример:

const { app } = require('electron');
const path = require('path');

// Правильный путь к файлам
const configPath = path.join(__dirname, 'config.json');
try {
  const config = require(configPath);
} catch (err) {
  console.error('Ошибка загрузки конфига:', err);
}

Проблема: Если используется __dirname в packaged приложении, путь может отличаться. Используйте app.getAppPath() для получения корневой папки приложения.

Расширенные примеры отладки ошибок главного процесса Electron

Полный обработчик ошибок с записью в файл и отправкой на сервер

Пример
// main.js
const { app, BrowserWindow, dialog } = require('electron');
const fs = require('fs');
const path = require('path');
const http = require('http');

const logError = (error) => {
  const logPath = path.join(app.getPath('userData'), 'error.log');
  const logEntry = `${new Date().toISOString()} ERROR: ${error.message}\n${error.stack}\n`;
  fs.appendFileSync(logPath, logEntry, 'utf8');
  // Отправка на сервер мониторинга
  const postData = JSON.stringify({ message: error.message, stack: error.stack });
  const req = http.request({
    hostname: 'errors.example.com',
    port: 80,
    path: '/log',
    method: 'POST',
    headers: { 'Content-Type': 'application/json' }
  });
  req.write(postData);
  req.end();
};

process.on('uncaughtException', (error) => {
  logError(error);
  dialog.showErrorBox('Критическая ошибка', 'Приложение будет закрыто.');
  app.quit();
});

process.on('unhandledRejection', (reason) => {
  logError(reason instanceof Error ? reason : new Error(String(reason)));
});

app.whenReady().then(() => {
  try {
    const win = new BrowserWindow({
      width: 1024,
      height: 768,
      webPreferences: {
        nodeIntegration: false,
        contextIsolation: true
      }
    });
    win.loadFile('index.html');
  } catch (err) {
    logError(err);
    app.quit();
  }
});

Результат: в папке userData создаётся файл error.log с деталями ошибки, а также отправляется POST-запрос на сервер.

Пример содержимого error.log:
2025-03-25T14:30:12.123Z ERROR: Cannot read property 'foo' of undefined
TypeError: Cannot read property 'foo' of undefined
    at app.whenReady (main.js:25:5)
    ...

Отладка главного процесса с помощью VS Code

Создать .vscode/launch.json:

Пример
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Отладка главного процесса Electron",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
      "runtimeArgs": ["./main.js", "--inspect=9229"],
      "sourceMaps": true,
      "protocol": "inspector",
      "console": "integratedTerminal"
    }
  ]
}

Запустите отладку через F5. В консоли VS Code отобразятся все console.log и ошибки. Можно ставить точки остановки прямо в main.js.

Использование remote модуля (устаревший способ)
Пример
// В main.js
const { BrowserWindow } = require('electron');

let win;
app.whenReady().then(() => {
  win = new BrowserWindow({
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false
    }
  });
  win.loadURL('data:text/html,<h1>Консоль в окне</h1><script>require("electron").remote.getCurrentWindow().webContents.openDevTools()</script>');
});

Результат:

Откроется окно с инструментами разработчика, в консоли которых доступен контекст главного процесса. Не рекомендуется использовать в продакшене.

Обработка ошибок в IPC
Пример
// main.js
const { ipcMain } = require('electron');

ipcMain.handle('dangerous-task', async (event, data) => {
  try {
    // Код, который может выбросить ошибку
    const result = JSON.parse(data);
    return result;
  } catch (err) {
    // Возвращаем ошибку в рендерер
    return { error: err.message };
  }
});

// В preload.js (contextBridge)
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('api', {
  dangerousTask: (data) => ipcRenderer.invoke('dangerous-task', data)
});

// В рендерере
async function runTask() {
  const result = await window.api.dangerousTask('invalid json');
  if (result.error) {
    console.error('Ошибка от главного процесса:', result.error);
  }
}

Результат: ошибка не уходит в uncaughtException, а обрабатывается внутри IPC-канала.

Ошибка JavaScript в главном процессе - comments

En
Javascript error occurred in the main process (javascript)