Security and quality

Debug and update deliberately

Use the correct DevTools, inspect main-process output, and keep Electron current without mixing dependency upgrades with feature work.

When something breaks in an Electron app, the first question is: which process owns the failing code? Renderer and preload messages show up in Chromium DevTools. Main-process errors show up in the terminal where you ran npm start. Look in the wrong place and you’ll see nothing, and conclude “it just doesn’t work”.

Open DevTools automatically, but only in development:

if (!app.isPackaged) {
  win.webContents.openDevTools({ mode: 'detach' })
}

app.isPackaged is false under npm start and true in the built app. The detach mode opens DevTools in its own window, so it doesn’t squash the notes interface.

Debugging an IPC failure

An IPC problem shows up in both places at once. The renderer sees a rejected promise with a generic message. The main process has the real error. Check both.

My sequence:

  1. Reproduce one action from a clean launch.
  2. Read the renderer rejection in the Console.
  3. Find the matching ipcMain.handle() and its terminal output.
  4. Check, in order: the sender check, the validator, the file path, the returned value.
  5. Repeat in the packaged app. Paths and bundles differ there, and a bug that only appears after npm run package is common.

Watch for process failures

A renderer can crash or hang without the main process noticing. Make those events loud during development:

win.on('unresponsive', () => {
  console.error('Main window became unresponsive')
})

app.on('render-process-gone', (_event, contents, details) => {
  console.error('Renderer exited', contents.id, details.reason)
})

unresponsive fires when the renderer stops answering for a while. render-process-gone fires when a renderer exits, and details.reason tells you whether it crashed, was killed, or ran out of memory.

While doing this, don’t log note bodies or credentials. Log IDs, operation names, and error categories. Debug output has a way of ending up in bug reports and screenshots.

Update on purpose

Electron bundles Chromium and Node.js. An Electron update is also a browser security update and a Node.js security update. Stay on a supported release line.

Upgrade one major version at a time. Read the breaking-changes page for that version, and the docs for that version, not “latest”. Then run, in this order: the Node tests, the renderer and IPC checks, the packaged-app checks, and the security checklist from this module. Only after that, touch other dependencies. Mixing an Electron bump with ten other upgrades makes a regression impossible to attribute.

After each upgrade, log process.versions.electron, process.versions.chrome, and process.versions.node from the main process. That’s the proof of which runtime the packaged app actually uses, whatever node --version says in your terminal.

Lesson completed