从 React 组件内部使用 Electron ipcRenderer
Using Electron's ipcRender from inside a React component
我正在尝试创建一个小型 React 应用程序来捕获和设置一个全局快捷方式,它将用于显示和隐藏 Electron 应用程序 window。但是我被卡住了,因为当我尝试从 React 组件内部使用 ipcRender 时,抛出了以下错误。
Uncaught Error: Cannot find module "fs"
我正在使用 Webpack 来捆绑我的 JS 并编译 JSX,并使用 ES6 语法来导入 Electron 和 ipcRender,你可以在下面的组件代码中看到。
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 设置为 'empty' 的节点对象,包括一个告诉 Webpack[=42] 的插件=] 忽略 fs 和 ipc 并通过 npm 安装 fs。我无法让他们中的任何一个工作。
不幸的是,我对 Webpack 或 ES6 语法的了解不够,无法弄清楚发生了什么,以及大多数解决方案我试过 'paste-and-hope' 时尚。因此,如果有人可以通俗地解释发生了什么,我将能够挖掘更多内容。
下面是我当前的 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'
}
};
您需要在您的 Webpack 配置中设置 target: 'electron-renderer'
,如果之后您仍然有问题,请查看 https://github.com/chentsulin/electron-react-boilerplate
通过使用 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>;
}
}
我正在尝试创建一个小型 React 应用程序来捕获和设置一个全局快捷方式,它将用于显示和隐藏 Electron 应用程序 window。但是我被卡住了,因为当我尝试从 React 组件内部使用 ipcRender 时,抛出了以下错误。
Uncaught Error: Cannot find module "fs"
我正在使用 Webpack 来捆绑我的 JS 并编译 JSX,并使用 ES6 语法来导入 Electron 和 ipcRender,你可以在下面的组件代码中看到。
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 设置为 'empty' 的节点对象,包括一个告诉 Webpack[=42] 的插件=] 忽略 fs 和 ipc 并通过 npm 安装 fs。我无法让他们中的任何一个工作。
不幸的是,我对 Webpack 或 ES6 语法的了解不够,无法弄清楚发生了什么,以及大多数解决方案我试过 'paste-and-hope' 时尚。因此,如果有人可以通俗地解释发生了什么,我将能够挖掘更多内容。
下面是我当前的 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'
}
};
您需要在您的 Webpack 配置中设置 target: 'electron-renderer'
,如果之后您仍然有问题,请查看 https://github.com/chentsulin/electron-react-boilerplate
通过使用 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>;
}
}