4

I am creating a new electron app but I met a problem I NEVER met

I used import {ipcRenderer} from 'electron' and used ipcRenderer.send, and it shows this error when Compiling Renderer Code.

In latest electron and electron forge, import electron and use it in ANY renderer code will cause error and terminate

I'm using React in electron, my previous project also used React+Electron, but it is okay to use electron module.

All things I can do is not working, including downgrade electron package.

Full logs:

yarn run v1.22.10
$ electron-forge start
√ Checking your system
√ Locating Application
√ Preparing native dependencies
√ Compiling Main Process Code
√ Launch Dev Servers
√ Compiling Preload Scripts
√ Launching Application


Webpack Output Available: http://localhost:9000


\ Compiling Renderer Code

An unhandled rejection has occurred inside Forge:
[Error: EISDIR: illegal operation on a directory, read] {
  errno: -4068,
  code: 'EISDIR',
  syscall: 'read'
}

Electron Forge was terminated. Location:
{}
error Command failed with exit code 1.

I tried re install all packages, but it's NOT work. Why & how to resolve? Even I add a target: 'node' to webpack.renderer.config.json, oh the window can finally show, but ipcRender CANNOT send message

Uncaught TypeError: Cannot read property 'send' of undefined
    at onClick (TitleBar.tsx?3219:11)
    at HTMLUnknownElement.callCallback (react-dom.development.js?6ac8:3945)
    at Object.invokeGuardedCallbackDev (react-dom.development.js?6ac8:3994)
    at invokeGuardedCallback (react-dom.development.js?6ac8:4056)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js?6ac8:4070)
    at executeDispatch (react-dom.development.js?6ac8:8243)
    at processDispatchQueueItemsInOrder (react-dom.development.js?6ac8:8275)
    at processDispatchQueue (react-dom.development.js?6ac8:8288)
    at dispatchEventsForPlugins (react-dom.development.js?6ac8:8299)
    at eval (react-dom.development.js?6ac8:8508)

WHY????

TheColdPot
  • 333
  • 1
  • 2
  • 9

4 Answers4

2

I met with the same problem still stuck on this

update: Use preload.js to access the main process' functions

2

tl;dr

Make webpack understand that electron should use require to import directly.

Solution

This is a webpack issue.

Webpack will pack all the packages that used into bundle. Because electron is a super cool package, webpack can not make it into bundle.

Config like this to make electron a commonjs2 module, make the statement from import electron from 'electron to require('electron') directly instead grab items from electron.

// webpack.renderer.config.js
module.exports = {
  externals: {
    electron: 'commonjs2 electron',
  },
}
TheColdPot
  • 333
  • 1
  • 2
  • 9
0

I got the same issue. I'm using Webpack + React

After investigated, I think it's because the webpack bundle issue. We cannot even use the package @electron/remote

Here is my workaround. I created a function in the preload.ts

Remember to use import * as electron from 'electron';

import * as electron from 'electron';

export function openDirectory(): void {
  const dialog = (electron as any).remote.dialog;
  console.log(
    dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] })
  );
}

enter image description here

Expose it by contextBridge

import { contextBridge } from 'electron';
import { getGitCommitLogs } from './core/git-api';
import { openDirectory } from './core/native-api';

contextBridge.exposeInMainWorld('getGitCommitLogs', getGitCommitLogs);
contextBridge.exposeInMainWorld('openDirectory', openDirectory);

enter image description here

Using it in the Renderer

enter image description here

Enable enableRemoteModule

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

enter image description here

I have posted my source code and issue https://github.com/electron-userland/electron-forge/issues/2384

Phat Tran
  • 3,404
  • 1
  • 19
  • 22
  • This is a great solution for that, but you have to declare all the methods in preload.ts. You can see my solution below (I read webpack documentation for a long time). Btw, thank you! – TheColdPot Nov 07 '21 at 08:55
0

The solution is using the ContextBridge API from electron for electron-forge react+webpack template

preload.js

import { ipcRenderer, contextBridge } from "electron";

contextBridge.exposeInMainWorld("electron", {
  notificationApi: {
    sendNotification(message) {
      ipcRenderer.send("notify", message);
    },
  },
  batteryApi: {},
  fileApi: {},
});

main.js

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

ipcMain.on("notify", (_, message) => {
   new Notification({ title: "Notification", body: message }).show();
});

package.json

 "plugins": [
    [
      "@electron-forge/plugin-webpack",
      {
        "mainConfig": "./webpack.main.config.js",
        "renderer": {
          "config": "./webpack.renderer.config.js",
          "entryPoints": [
            {
              "html": "./src/index.html",
              "js": "./src/renderer.js",
              "name": "main_window",
              "preload": {
                "js": "./src/preload.js"
              }
            }
          ]
        }
      }
    ]
  ]

app.jsx

import * as React from "react";
import * as ReactDOM from "react-dom";

class App extends React.Component {
  componentDidMount() {
    electron.notificationApi.sendNotification("Finally!");
  }
  render() {
    return <h1>contextBridge</h1>;
  }
}

ReactDOM.render(<App />, document.body);
Sathishkumar Rakkiyasamy
  • 3,509
  • 2
  • 30
  • 34
  • Thanks, but I found a better way after spend a lot of time on reading webpack documentation. Check it below, it might solve your problem too! – TheColdPot Nov 07 '21 at 08:56