Why can my second window not access ipcRenderer in Electron

Viewed 116

I'm creating a Electron React TypeScript app and came across a problem with electron contextBridge

I have two windows, each with their own page. In the OverviewPage (and the main window),I don't have problems to access functions that are exposed via contextBridge.exposeInMainWorld in the preload file. However, if I try to access the same api-calls on the SelfReport page, I get following error

Uncaught TypeError: Cannot read properties of undefined (reading 'closePopup')

My preload.ts

const { ipcRenderer, contextBridge } = require("electron");

contextBridge.exposeInMainWorld("api", {
 
  closePopup: (args: any) => ipcRenderer.send("close-popup", args)
  // other calls
});
export {};

In Main.ts Main Window

function createWindow(width: any, height: any) {
  const mainWindow = new BrowserWindow({
    width: width,
    height: height,
    fullscreen: true,
    webPreferences: {
      contextIsolation: true,
      preload: path.join(__dirname, "/preload.js"),
    },
  });
  if (app.isPackaged) {
    mainWindow.loadFile(path.join(__dirname, "../index.html"));
  } else {
    mainWindow.loadURL("http://localhost:3000");
  }

In Main.ts Second Window

let popupWindow;
function createPopupWindow(width: any, height: any) {
  popupWindow = new BrowserWindow({
    frame: false,
    resizable: false,
    movable: false,
    focusable: false,
    alwaysOnTop: true,
    skipTaskbar: true,
    height: 300,
    width: 400,
    x: width - 400,
    y: height - 300,

    webPreferences: {
      webPreferences: {
        contextIsolation: true,
        //preload: path.join(__dirname, "/preload.js"),    Do I need this?
      },
    },
  });
  Menu.setApplicationMenu(null);
  popupWindow.loadURL("http://localhost:3000/report"); 
}

In React

window.api.closePopup({ close: true });

and

class App extends Component {
    componentDidMount() {}

    render() {
        return (
            <BrowserRouter>
                <Switch>
                    <Route element={<WithNavbar />}>
                        <Route path="/" element={<OverviewPage />} />          
                    </Route>
                    <Route element={<WithoutNavbar />}>
                        <Route path="/report" element={<SelfReport />} />
                    </Route>
                </Switch>
            </BrowserRouter>
        );
    }
}

In react-app-env.d.ts

/// <reference types="react-scripts" />

declare global {
    interface Window {
        api: any;
    }
}
export {};

Note

  • When starting my application, I'm using the built preload.js version.
  • All React Pages are Function Components
1 Answers

Your Main.ts (second window) has an extra level of webPreferences. That extra level can be removed.

Also, you should un-comment your preload: line for your window.api.closePopup call to work.


Main.ts (second window)

let popupWindow;

function createPopupWindow(width: any, height: any) {
    popupWindow = new BrowserWindow({
        frame: false,
        resizable: false,
        movable: false,
        focusable: false,
        alwaysOnTop: true,
        skipTaskbar: true,
        height: 300,
        width: 400,
        x: width - 400,
        y: height - 300,
        webPreferences: {
            contextIsolation: true,
            preload: path.join(__dirname, "/preload.js") // Do I need this? Yes
        }
    });

    Menu.setApplicationMenu(null);
    popupWindow.loadURL("http://localhost:3000/report"); 
}
Related