AOG Poston
a software engineer

How do I use dialog with Cawa-93's Electron boilerplate?
by AOGPoston on 05/01/24

Recently, I've been rewriting an electron app. The previous project was riddled with dependency issues and used Vue 2 without typescript. I stumbled on Cawa-93's vite-electron-builder git repo and saw it had everything I could ask for. After a few months of development, I ran into an issue.

I couldn't figure out how to get electron's dialog box to work in with this new file structure. Now, this is a very niche problem, so if you have it, I suspect I don't need to hash the finer details. Sufficed to say, I have figured out a solution and am passing it along.

Step 1: Write the handler in Main

The boilerplate is split into 3 packages. Main, preload, and renderer. Main handles the instantiation of the electron window. When the window is declared to be ready, we want to write some functions and tell electron how to handle their invocation.

Add dialog and ipcMain to the imports from electron:

import { app, dialog, ipcMain } from "electron";

Find this in your codebase:

//packages/main/src/index.ts ....

app
  .whenReady()
  .then(restoreOrCreateWindow)
  .catch((e) => console.error("Failed create window:", e));

After the window is created, add a handler to ipc main.

//packages/main/src/index.ts ....

app
  .whenReady()
  .then(restoreOrCreateWindow)
  .then(() => {
    ipcMain.handle("an-action", async (event: any, arg: any) => {
      const d = await dialog.showOpenDialog({
        properties: ["openFile", "multiSelections"],
      });
      return d;
    });
  })
  .catch((e) => console.error("Failed create window:", e));

You can add any number of handlers here, and you have access to all of electrons dialog features here in main.

Step 2: Invoke the handler in preload

This is my implementation. I believe its cleaner in the codebase to invoke this using the preload exports Cawa built out. So, here is how I implemented it.

//packages/preload/src/index.ts

import { ipcRenderer } from "electron";
export async function someFunction() {
  const file = await ipcRenderer.invoke("an-action", [1, 2, 3]);
}

Then you can use const file:

//packages/preload/src/index.ts

try {
  const backup = JSON.parse(await readFile(file.filePaths[0], "utf8"));
} catch (e) {}

Nice.