【问题标题】:Using Electron's ipcRender from inside a React component从 React 组件内部使用 Electron ipcRenderer
【发布时间】:2017-01-12 22:33:12
【问题描述】:

我正在尝试创建一个小型 React 应用程序,它捕获并设置一个全局快捷方式,用于显示和隐藏 Electron 应用程序窗口。但是我卡住了,当我尝试从 React 组件内部使用 ipcRender 时,会引发以下错误。

Uncaught Error: Cannot find module "fs"

我正在使用 Webpack 来捆绑我的 JS 并编译 JSX,并使用 ES6 语法来导入 ElectronipcRender,正如您在下面的组件代码中看到的那样。

import React from "react";
import electron, { ipcRenderer } from 'electron';

var event2string = require('key-event-to-string')({});

export default React.createClass({
    getInitialState: function() {
        return {shortcut: this.props.globalShortcut[0]};
    },
    handleOnKeyDown:function(e){
        e.preventDefault();
        var keys = event2string(e);
        this.setState({shortcut:keys});

        this.props.globalShortcut.splice(0, 1);
        this.props.globalShortcut.push(keys);
    },
    handleOnKeyUp:function(){
        this.refs.shortcutInput.value = this.state.shortcut;
        this.refs.shortcutInput.blur();
        ipcRenderer.send('set-new-shortcut', this.props.globalShortcut);
    },
    handleOnFocus:function(){
        this.refs.shortcutInput.value = '';
    },
    render() {
        return (
            <div id="settings-container">
                <h1>The show/hide shortcut is "{this.state.shortcut}"</h1>
                <form role="form">
                    <input type="text" ref="shortcutInput" placeholder="Create new shortcut" onFocus={this.handleOnFocus} onKeyDown={this.handleOnKeyDown} onKeyUp={this.handleOnKeyUp} className="form-control form-field"/>
                </form>
            </div>
        );
    }
});

我尝试了不同的解决方案,例如将 node-loader & json-loader 添加到我的 Webpack 文件中,添加节点fs 设置为“空”的对象,包括一个告诉 Webpack 忽略 fsipc 并安装的插件fs 通过 npm。我不能让他们中的任何一个工作。

不幸的是,我没有足够的 WebpackES6 语法知识来弄清楚发生了什么,而且我尝试过的大多数解决方案都是在“粘贴和希望”时尚。因此,如果有人可以用外行的话解释发生了什么,我将能够挖掘更多。

下面是我当前的 Webpack 文件。

var webpack = require('webpack');

module.exports = {
  context: __dirname + '/src/js',
  entry: "./index.js",

  output: {
    filename: 'bundle.js',
    path: __dirname + '/build',
    publicPath: 'http://localhost:8080/build/'
  },

  module: {
    loaders: [
      { test: /\.jsx?$/, loader: 'babel-loader', exclude: /node_modules/, query:{presets:['es2015','react']} },
      { test: /\.scss$/, loader: 'style-loader!css-loader!sass-loader' }
    ]
  },

  // Don't know if below is working, 'Uncaught Error: Cannot find module "fs"' error still thrown when trying to import electron
  plugins: [ 
    new webpack.IgnorePlugin(new RegExp("^(fs|ipc)$"))
  ],

  // Don't know if below is working, 'Uncaught Error: Cannot find module "fs"' error still thrown when trying to import electron
  node: {
    fs: 'empty'
  }
};

【问题讨论】:

  • fs 是一个模块。尝试导入/要求
  • 我刚刚尝试在import electron, { ipcRenderer } from 'electron'; 之前添加import fs from 'fs'; 并且仍然抛出错误。我还尝试了通过 npm --save-dev 安装的 fs
  • 这是我的 bundle.js var _fs = __webpack_require__(!(function webpackMissingModule() { var e = new Error("Cannot find module \"fs\""); e.code = 'MODULE_NOT_FOUND'; throw e; }())); 中发生错误的地方@

标签: javascript node.js reactjs ecmascript-6 electron


【解决方案1】:

通过contextBridge我们可以解决这个问题

const { app, BrowserWindow, ipcMain, Notification } = require("electron");

new BrowserWindow({
    width: 1200,
    height: 800,
    backgroundColor: "white",
    webPreferences: {
      nodeIntegration: false,
      worldSafeExecuteJavaScript: true,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js')
    }
  })

//example to display notification
ipcMain.on('notify', (_, message) => {
   new Notification({title: 'Notification', body: message}).show();
})

preload.js

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

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

然后在您的 reactjs 组件中使用以下代码将触发原生通知消息

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

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

【讨论】:

    【解决方案2】:

    你需要在你的 Webpack 配置中设置target: 'electron-renderer',如果之后你仍然有问题,请查看https://github.com/chentsulin/electron-react-boilerplate

    【讨论】:

    • 这已经奏效了!但是已经阻止了我当地的开发环境的工作。我将通过 electron-react-boilerplate github 了解一下原因。你能解释一下为什么 target: 'electron-renderer' 是必需的吗?或者给我指出一篇需要的文章?
    • @adotellison 我认为官方文档没有涵盖它,但this module 是在将 Electron 目标集成到 Webpack 之前的方法。我自己从未使用过 Webpack,因此无法真正解释为什么或如何使用,我只能为您指出正确的方向,因为我回答这个问题的次数比我想记住的要多。
    猜你喜欢
    • 2022-01-27
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 2016-06-19
    • 2022-06-10
    • 1970-01-01
    • 2017-04-30
    • 2021-10-21
    相关资源
    最近更新 更多