【问题标题】:How to import the electron ipcRenderer in a react / webpack 2 setup如何在 react / webpack 2 设置中导入电子 ipcRenderer
【发布时间】:2017-10-15 23:04:05
【问题描述】:

使用电子、反应 (es6 / jsx)、sass、pouchdb 和 webpack 2 设置。我无法导入或要求 ipcRenderer 使主进程和渲染器进程之间的通信成为可能。我的设置可以在这里找到:https://github.com/wende60/timeTracker

任何提示如何将 ipcRenderer 放入反应组件?

干杯,乔

【问题讨论】:

    标签: reactjs webpack electron


    【解决方案1】:
    const electron = window.require('electron');
    const ipcRenderer  = electron.ipcRenderer;
    

    我认为这是更好的解决方案,因为它避免了弹出 React 应用程序。

    【讨论】:

    【解决方案2】:

    我遇到了同样的问题。这为我解决了这个问题:

    添加webpack.config.js:

    const webpack = require("webpack");
    
    module.exports = {
        plugins: [
            new webpack.ExternalsPlugin('commonjs', [
                'electron'
            ])
        ]
        ...
    }
    

    然后你就可以用它了

    import {ipcRenderer} from "electron";
    

    【讨论】:

    • 感谢马蒂亚斯的提示。我找到了一个使用 webpack-target-electron-renderer 的替代解决方案,如下所示:github.com/wende60/timeTracker 所以我可以开发 react、scss 和 pouchdb-access 运行 'web' 与热重载和导入电子只有当我运行'电子'欢呼, 乔
    • 这很好用,很想知道你是怎么知道这样做的
    • The externals configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency to be present in the consumer's (any end-user application) environment. 那么这是否意味着该解决方案仅在用户安装电子的前提下才有效?
    【解决方案3】:

    我建议你阅读我的回复here

    您需要像这样设置您的应用:

    ma​​in.js

    const {
      app,
      BrowserWindow,
      ipcMain
    } = require("electron");
    const path = require("path");
    const fs = require("fs");
    
    // Keep a global reference of the window object, if you don't, the window will
    // be closed automatically when the JavaScript object is garbage collected.
    let win;
    
    async function createWindow() {
    
      // Create the browser window.
      win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: false, // is default value after Electron v5
          contextIsolation: true, // protect against prototype pollution
          enableRemoteModule: false, // turn off remote
          preload: path.join(__dirname, "preload.js") // use a preload script
        }
      });
    
      // Load app
      win.loadFile(path.join(__dirname, "dist/index.html"));
    
      // rest of code..
    }
    
    app.on("ready", createWindow);
    
    ipcMain.on("toMain", (event, args) => {
      fs.readFile("path/to/file", (error, data) => {
        // Do something with file contents
    
        // Send result back to renderer process
        win.webContents.send("fromMain", responseObj);
      });
    });
    

    preload.js

    ** 更新:不要使用 send 键值作为属性名称。它将覆盖win.webContents.send 方法,当您尝试在主进程main.js 中调用win.webContents.send('your_channel_name') 时,它什么也不做。最好使用更好的名称,例如 requestresponse

    const {
        contextBridge,
        ipcRenderer
    } = require("electron");
    
    // Expose protected methods that allow the renderer process to use
    // the ipcRenderer without exposing the entire object
    contextBridge.exposeInMainWorld(
        "api", {
            //send: (channel, data) => {
            request: (channel, data) => {
                // whitelist channels
                let validChannels = ["toMain"];
                if (validChannels.includes(channel)) {
                    ipcRenderer.send(channel, data);
                }
            },
            //receive: (channel, func) => {
            response: (channel, func) => {
                let validChannels = ["fromMain"];
                if (validChannels.includes(channel)) {
                    // Deliberately strip event as it includes `sender` 
                    ipcRenderer.on(channel, (event, ...args) => func(...args));
                }
            }
        }
    );
    

    index.html

    <!doctype html>
    <html lang="en-US">
    <head>
        <meta charset="utf-8"/>
        <title>Title</title>
    </head>
    <body>
        <script>
            window.api.response("fromMain", (data) => {
                console.log(`Received ${data} from main process`);
            });
            window.api.request("toMain", "some data");
        </script>
    </body>
    </html>
    

    【讨论】:

    • @Sajad - 我已经使用上述方法编写了代码,您在使用 send 作为 preload.js 的窗口属性时遇到了什么问题?
    • 我尝试使用 win.webContents.send('channel', someArgs) 将某个键盘快捷键上的主进程中的事件发送到我的 ipcRendere,但未能在 ipcRendere.on('channel', func()) 中接收数据。花了 1 个小时才发现问题是当您尝试使用 contextBridge.exposeInMainWorldapi.sendapi.receive 方法附加到窗口对象时,它将影响 win.webContents.send 方法并且您将丢失 data arg 内容, 导致你的调用函数不是 webContents.send 方法。
    • 这是我目前所知道的一切,我将尝试找出“contextBridge.exposeInMainWorld”的正确行为。但我确实将send 更改为request,我现在一切都很好......
    • 我目前在电子 12 上使用这种方法,未​​弹出的 CRA(create-react-app)似乎是干净的工作解决方案......
    【解决方案4】:

    截至 2020 年 5 月,我认为Erik Martín Jordán has said it best

    创建一个 preload.js 文件:

    window.ipcRenderer = require('electron').ipcRenderer;
    

    在 main.js 上:

    
    // Create the browser window.
    mainWindow = new BrowserWindow({
        alwaysOnTop: true,
        frame: false,
        fullscreenable: false,
        transparent: true,
        titleBarStyle: 'customButtonsOnHover',
        show: false,
        width: 300, 
        height: 350,
        webPreferences: {
            // UPDATE: for electron > V12 consider setting contextIsolation and see: https://github.com/electron/electron/issues/9920#issuecomment-797491175
            nodeIntegration: true,
            preload: __dirname + '/preload.js'
        }
    });
    
    // Blur window when close o loses focus
    mainWindow.webContents.on('did-finish-load', () => mainWindow.webContents.send('ping', '?') );
    

    此文件上的 mainWindow 变量将预加载 preload.js 文件。现在 React 组件可以调用 window.ipcRenderer 方法了。

    在 React app.js 中:

    import React, { useEffect, useState } from 'react';
    import './App.css';
    
    function App() {
        
        useEffect( () => {
            
            window.ipcRenderer.on('ping', (event, message) => { 
                console.log(message) 
            });
                    
        }, []);
                
        return (
        <div className = 'App'></div>
        );
    }
    
    export default App;
    

    【讨论】:

      【解决方案5】:

      我最近一直在研究这个话题,我找到了一个解决方案,可以在电子 main.js 和应用程序的 React 部分之间做一些 ipc。由于两者,import {ipcRenderer} from 'electron'; 在将插件添加到 webpack 模块后和const ipc = require('electron').ipcRenderer; 都产生了一些错误,我最终需要在结果页面中使用电子并将其添加到窗口中。

      index.html我做了这样的事情

      <body>
        ...
        <script>
          window.ipc = require('electron').ipcRenderer;
        </script>
        <div id="root">
        </div>
        ...
      </body>
      

      在反应index.js 我做了这样的事情:

      import React from 'react';
      import ReactDOM from 'react-dom';
      // ...
      if(window.ipc)
      ipc.on("some-event", (event, someParameter) => {
        ReactDOM.render(
          <SomeElement value={someParameter} />,
          document.getElementById("root")
        );
      })
      // ...
      

      为了完成这项工作,我从电子应用程序启动了反应页面,在 main.js 我做了类似的事情。

      const {app, BrowserWindow} = require("electron"};
      const exec = require("child_process").exec;
      
      let main;
      app.on("ready", () => {
        exec("node start", (err, stdout, stderr) => {
          if(err) console.log(err);
          console.log("" + stdout);
          console.log("" + stderr);
        });
      
        main = new BrowserWindow();
        main.loadURL("http://localhost:3006");
        main.on("close", () => {main = null});
      });
      

      因为 electron 在同一个端口上运行,所以我在我的项目中添加了一个 .env 文件,其中包含

      PORT=3006
      

      我在我的基础项目中使用了create-react-app my-prj (npm install -g create-react-app) 命令,它看起来像这样

      my-prj
       |-package.json
       |-main.js
       |-.env
       |-node_modules/
       |-public/
          |-index.html
       |-src/
          |-index.js
      

      希望这篇文章对您有所帮助。

      【讨论】:

        【解决方案6】:

        使用webpack-target-electron-renderer 为这个问题找到了一个很好的解决方案,所以我可以在本地主机环境中使用热重载开发 Web 部件。 electron 仅在电子环境中是必需的。

        您可以在此处查看一个工作示例: https://github.com/wende60/webpack-web-and-electron-example,来自 acao 的 webpack-web-and-electron-example 并针对 webpack 2 和热替换进行了更新。

        如果你对 webpack、electron、react、sass 和 pouchdb 设置感兴趣,请看这里: https://github.com/wende60/timeTracker 工作仍在进行中...

        【讨论】:

          【解决方案7】:
          import { ipcRenderer } from "electron"
          import { Component } from "react"
          

          ...

          class MyComponent extends Component {
             render(){
                ipcRenderer.send("event", "some data")
                return (<div>Some JSX</div>)
             }
          }
          

          【讨论】:

          • 嗨 Sators,这是我 - 当然 - 之前尝试过的东西,但我最终得到了类似的结果:bundle.js:49593 未捕获的错误:找不到模块“fs” 在 webpackMissingModule (bundle.js:49593) 在 Object. (bundle.js:49593) 在 Object.splitPathRe (bundle.js:49604) 在 webpack_require (bundle.js: 658) 在 fn (bundle.js:86) ... npm install fs 不是这里的解决方案...
          猜你喜欢
          • 1970-01-01
          • 2016-08-13
          • 2018-06-17
          • 1970-01-01
          • 2021-08-11
          • 2020-12-16
          • 2017-03-07
          • 2020-11-03
          • 2018-10-03
          相关资源
          最近更新 更多