使用 electron ipc 时,Electron forge 停止遵守渲染器代码

Electron forge stopped in complies renderer code when using electron ipc

我正在创建一个新的 Electron 应用程序,但我遇到了一个从未遇到过的问题

我用了import {ipcRenderer} from 'electron',用了ipcRenderer.send,在编译Renderer Code的时候显示这个错误

在最新的 electron 和 electron forge 中,导入 electron 并在任何渲染器代码中使用它都会导致错误并终止

我在electron里用的是React,我之前的项目也是用的React+Electron,不过用electron模块没问题

我能做的所有事情都不起作用,包括降级电子包。

完整日志:

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.

我尝试重新安装所有软件包,但没有用。 为什么以及如何解决? 即使我在webpack.renderer.config.json中添加了一个target: 'node',哦window终于可以显示了,但是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)

为什么????

我遇到了同样的问题,仍然卡在这个

更新:使用preload.js访问主进程的功能

我遇到了同样的问题。我正在使用 Webpack + React

经过调查,我认为是因为webpack bundle的问题。我们甚至不能使用包 @electron/remote

这是我的解决方法。我在 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'] })
  );
}

通过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);

在渲染器中使用它

启用enableRemoteModule

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

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

解决方案是使用 electron 中的 ContextBridge API for electron-forge react+webpack 模板

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);

tl;博士

让webpack明白electron应该使用require直接导入

解决方案

这是一个 webpack 问题。

Webpack 会将所有使用到的包打包成 bundle。因为 electron 是一个超酷 包,webpack 可以不能 将其打包。

像这样配置使电子成为commonjs2模块,直接从import electron from 'electronrequire('electron')声明而不是从电子中获取项目。

// webpack.renderer.config.js
module.exports = {
  externals: {
    electron: 'commonjs2 electron',
  },
}