在Electron中,如何在我的React代码中启用NodeJS?

huangapple go评论65阅读模式
英文:

In Electron, how do I enable NodeJS inside my React Code?

问题

在Electron中,要在React代码中启用NodeJS,你需要采取以下步骤:

  1. 首先,在Electron的主应用程序窗口(main window)中启用NodeJS,可以通过以下方式设置Electron的webPreferences
webPreferences: {
  contextIsolation: false,
  nodeIntegration: true, // 允许在Web页面中调用NodeJS代码
  enableRemoteModule: true
}

确保你的Electron主窗口的webPreferences中的nodeIntegration属性设置为true,这样才能在你的React代码中使用NodeJS模块。

  1. 然后,在你的React代码中,你可以使用以下方式来引入fs模块:
const fs = window.require('fs');

在React代码中,你可以使用window.require来引入NodeJS模块,因为在上面的步骤中已经启用了nodeIntegration

通过这两个步骤,你应该能够在Electron中启用NodeJS并在React代码中使用fs模块来访问文件系统组件。不要忘记遵循安全性最佳实践,以确保你的应用程序的安全性。

英文:

In Electron, how do I enable NodeJS inside my React Code?

What are the steps I need to take? I'm trying to access the file system component which is normally accessed in node using:

const fs = require('fs');

Inside my React code this didn't compile, so I tried changing it to import and it also did not work.

import fs from 'fs';
// Gives error
Module not found: Error: Can't resolve 'fs' ...

Searching for a solution I found some questions but not an answer (yet):

I saw a SO question/answer that matched this but now I can't find it!

I've already enabled NodeJS in my Electron main app using:

  mainWindow = new BrowserWindow({
    width: winState.width,
    height: winState.height,
    x: winState.x,
    y: winState.y,
    webPreferences: {
      // --- !! ANT !! ---
      // Disable 'contextIsolation' to allow 'nodeIntegration'
      // 'contextIsolation' defaults to "true" as from Electron v12
      contextIsolation: false,
      nodeIntegration: true, /* Allow NodeJS code to be called in Web Pages */
      enableRemoteModule: true
    }
  })

答案1

得分: 1

在Electron应用程序中使用React进行文件系统访问,您的代码库需要三个不同部分:

  • 主进程在Node中运行,并具有对fs和Node的所有其他功能的访问权限。最终可能会调用new BrowserWindow,打开一个窗口并运行预加载脚本

  • 预加载脚本用于管理主进程和浏览器之间的通信。虽然它可以执行更多操作,但实际上不应该这样做;最好让它仅充当一个桥梁。您的预加载脚本可能只需像这样简单:

    contextBridge.exposeInMainWorld('electronAPI', {
      sendMessageToMainProcess: (channel, payload) => ipcRenderer.invoke(channel, payload),
    })
    
  • 页面脚本运行React代码(以及在窗口中运行的任何其他代码)。它在类似浏览器的上下文中运行,没有访问任何Node函数的权限。为了从页面动态读取文件系统,页面将需要向主进程发送消息(通过预加载脚本公开的API),然后主进程将需要监听消息,运行所需的fs操作,然后用结果回复消息。上面的electronAPI示例可以从React中调用window.electronAPI.sendMessageToMainProcess(channel, payload)。主进程可以监听消息(通过预加载脚本附加),并使用以下方式回复消息,例如

    ipcMain.handle('someChannelName', (event, payload) => {
      // 在此进行验证(如果需要)...
      return fs.promises.readFile('somepath', 'utf-8')
        // .catch(handleErrors);
    });
    

通过从处理程序函数返回Promise,Promise解析的值将发送回调用者。

上述设置非常容易进行,并且不需要不安全的contextIsolation: falsenodeintegration: true

> 从Electron 12开始,默认启用了上下文隔离,并且它是所有应用程序的建议安全设置。

如果页面脚本中的任何代码不是您自己编写的(例如,如果您使用外部库或少数库,如React),那么您不应允许页面脚本直接访问Node或文件系统。

英文:

For filesystem access inside an Electron app with React, you will need three different sections of your codebase:

  • The main process, which runs in Node and has access to fs and everything else Node has. This may eventually call new BrowserWindow, which opens a window and runs the preload script.

  • The preload script is meant to manage communication between the main process and the browser. While it can do more, it really, really shouldn't; it's best for it to act only as a bridge. Your preload script may be as simple as something like

    contextBridge.exposeInMainWorld('electronAPI', {
      sendMessageToMainProcess: (channel, payload) => ipcRenderer.invoke(channel, payload),
    })
    
  • Your page script, which runs the React code (and any other code that runs in the window). This runs in a context similar to a browser and doesn't have access to any Node functions. In order to dynamically read from the filesystem from the page, the page will need to send a message to the main process (over the API exposed by the preload script), and then the main process will need to listen for messages, run whatever fs operations are needed, and then reply to the message with the result. The electronAPI example above can be invoked from React with window.electronAPI.sendMessageToMainProcess(channel, payload). The main process can listen for messages (attached via the preload script) and reply to them with, for example

    ipcMain.handle('someChannelName', (event, payload) => {
      // do verification here if desired...
      return fs.promises.readFile('somepath', 'utf-8')
        // .catch(handleErrors);
    });
    

    By returning a Promise from the handler function, the value that the Promise resolves to will be sent back to the caller.

The above is pretty easy to set up and doesn't require the unsafe contextIsolation: false nor nodeintegration: true:

>Context isolation has been enabled by default since Electron 12, and it is a recommended security setting for all applications.

If any of the code in the page script is not personally your own (for example, if you use an external library or few - such as React), then you should not allow the page script direct access to Node or your filesystem.

答案2

得分: 0

在Electron应用程序中,使用NodeJS的require函数的方法是使用如下方式使用window.require

const fs = window.require('fs');

只有在创建BrowserWindow时首先启用了nodeIntegration: true才能起作用。

mainWindow = new BrowserWindow({
      nodeIntegration: true, 
});

正如@CertainPerformance所说,这实际上是一种巧妙的方法。我在刚开始学习时使用它,因为它比学习如何通过Electron IPC机制(ipcRenderer.invoke)实现相同功能要简单得多。

英文:

In an Electron app, the way to use the NodeJS require function is to use window.require as shown below:

const fs = window.require('fs');

This only works if you've first enabled nodeIntegration: true when creating the BrowserWindow.

mainWindow = new BrowserWindow({
      nodeIntegration: true, 
});

As @CertainPerformance, says this is really a hack. I used it when first getting started because it was easier than learning how to do the equivalent functionality via the Electron IPC mechanism (ipcRenderer.invoke)

huangapple
  • 本文由 发表于 2023年1月9日 11:14:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定