Using electron save dialog in renderer with context isolation

Viewed 650

I need to be able to open a save dialog in my electron app. With the remote module now being recommended to not use in the renderer, I'm having a hard time getting this to work. I use a preload script to setup an IPC api to do some things I once used the remote module for. I don't however want to use an IPC message to open save dialogs.

I would assume that I should just import the remote module into my preload script and add the dialog object to window so I can use it in the renderer. This doesn't seem to work and remote is undefined.

What is the proper way to expose the save/open dialogs to the renderer now?

main.js

const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      worldSafeExecuteJavaScript: true,
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
    },
  });

preload.js

import { ipcRenderer, contextBridge, remote } from 'electron';

console.log(remote); // undefined

contextBridge.exposeInMainWorld('electron', {
  API: ...,
  dialog: remote.dialog,
});

Importing all of electron and logging that does not have a remote object. I did also try adding "enableRemoteModule: true" but that did not work either.

1 Answers

Use IPC for that. Send action from Renderer to Main that you want to open the Dialog. Main listens that message and opens Dialog from Main process.

Renderer

import { ipcRenderer, contextBridge } from 'electron';

contextBridge.exposeInMainWorld('electron', {
  API: ...,
  openDialog: () => {
    ipcRenderer.send('open-dialog') // adjust naming for your project
  },
  // Provide an easier way to listen to events
  on: (channel: string, callback: Function) => {
    ipcRenderer.on(channel, (_, data) => callback(data));
  },
});

In DOM Event:

window.electron.openDialog();
window.electron.on('on-file-select', (path) => {
  console.log(path)
})

Main

let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      worldSafeExecuteJavaScript: true,
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
    },
  });
}

function registerListeners() {
  ipcMain.on('open-dialog', (event) => {
    dialog
      .showOpenDialog(mainWindow!, {
        properties: ['openFile']
      })
      .then(({ filePaths }) => {
        if (filePaths.length) {
          event.reply('on-file-select', filePaths[0]);
        }
      });
  })
}

app
  .on('ready', createWindow)
  .whenReady()
  .then(registerListeners)
Related