本文介绍了如何在Electron中正确使用preload.js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我正在尝试在 renderer 进程中使用Node模块(在本示例中为 fs ),例如 // main_window.js const fs = require('fs') function action(){ console.log(fs)} 但这会产生错误: 未捕获的ReferenceError:require是在main_window.js中未定义:1 我可以解决此问题,按照已接受的答案建议,方法是将这些行添加到我的 main.js 初始化 main_window 时: // main.js main_window = new BrowserWindow({宽度:650,高度:550, webPreferences:{ nodeIntegration:true } }) 但是,根据文档,这不是最好的选择,我应该改为创建一个 preload.js 文件并在其中加载这些Node模块,然后在我的所有 renderer 中使用它流程。像这样: main.js : main_window = new BrowserWindow({宽度:650,高度:550, webPreferences:{ preload:path.join(app。 getAppPath(),'preload.js')} }) preload.js : const fs = require('fs') window.test = function(){ console.log(fs)} main_window.js : function action(){ window.test()} 现在我的问题是,我应该编写大部分代码不是违反直觉的吗?我在 preload.js 中的 renderer 进程(仅在 preload.js 我可以访问Node模块),然后只调用每个 renderer.js 文件中的函数(例如,这里的 main_window.j) s )?我在这里不明白什么? 解决方案 编辑 根据另一个用户的要求,让我解释一下下面的答案。 在Electron中使用 preload.js 的正确方法是在所有模块周围公开白名单包装器您的应用可能需要 require 。 从安全角度而言,暴露 require很危险,或通过 preload.js 中的 require 调用检索到的任何内容(请参见我在这里的评论以了解更多原因)。如果您的应用加载了远程内容,这尤其如此。 为了正确执行操作,您需要在 BrowserWindow ,下面将详细介绍。设置这些选项将强制您的电子应用通过IPC(进程间通信)进行通信,并将两个环境彼此隔离。像这样设置您的应用程序,使您可以验证后端中可能是需求'模块的任何内容,而客户端不会对其进行改动。 下面,您会找到一个简短的示例,说明我所说的内容以及它在您的应用程序中的外观。如果您是新手,建议您使用 secure-electron-template (我是作者),在构建电子应用程序时一开始就考虑了所有这些安全最佳实践。 此页面也有很好的信息 main.js main.js const {应用程序, BrowserWindow, ipcMain } = require( electron); const path = require( path); const fs = require( fs); //保留窗口对象的全局引用,否则,当JavaScript对象被垃圾回收时,窗口将自动关闭 //。 让胜利; 异步函数createWindow(){ //创建浏览器窗口。 win = new BrowserWindow({宽度:800,高度:600, webPreferences:{ nodeIntegration:false,//是Electron v5之后的默认值 contextIsolation:true,//防止原型污染 enableRemoteModule:false,//关闭远程 preload:path.join(__ dirname, preload.js)//使用预加载脚本} }); //加载应用程序 win.loadFile(path.join(__ dirname, dist / index.html)); //其他代码。} app.on( ready,createWindow); ipcMain.on( toMain,(事件,args)=> { fs.readFile( path / to / file,(错误,数据)=> { //对文件内容执行操作 //将结果发送回渲染器进程 win.webContents.send( fromMain,responseObj); }) ; }); preload.js const { contextBridge, ipcRenderer } = require( electron); //公开受保护的方法,这些方法允许渲染器进程使用 // ipcRenderer而不暴露整个对象 contextBridge.exposeInMainWorld( api,{ send:(channel,data)=> { //将频道加入白名单 let validChannels = [ toMain]; if(validChannels.includes(channel)){ ipcRenderer.send(channel,data); } },接收:(channel,func)=> { let validChannels = [ fromMain ]; if(validChannels.includes(channel)){ //故意剥离事件,因为它包含`sender` ipcRenderer.on(channel,(event,... args)= > func(... args)); } } } ); index.html <!doctype html> < html lang = zh-CN> < head> < meta charset = utf-8 /> < title>标题< / title> < / head> < body> < script> window.api.receive( fromMain,(data)=> { console.log(`从主进程接收到$ {data}); }); window.api.send( toMain,一些数据); < / script> < / body> < / html> I'm trying to use Node modules (in this example, fs) in my renderer processes, like this:// main_window.jsconst fs = require('fs')function action() { console.log(fs)}But this gives an error:Uncaught ReferenceError: require is not defined at main_window.js:1I can solve this issue, as suggested by this accepted answer, by adding these lines to my main.js when initializing the main_window:// main.jsmain_window = new BrowserWindow({ width: 650, height: 550, webPreferences: { nodeIntegration: true }})But, according to the docs, this isn't the best thing to do, and I should instead, create a preload.js file and load these Node modules there and then use it in all of my renderer processes. Like this:main.js:main_window = new BrowserWindow({ width: 650, height: 550, webPreferences: { preload: path.join(app.getAppPath(), 'preload.js') }})preload.js:const fs = require('fs')window.test = function() { console.log(fs)}main_window.js:function action() { window.test()}And it works!Now my question is, isn't it counter-intuitive that I should write most of the code of my renderer processes in preload.js (Because only in preload.js I have access to Node modules) and then merely call the functions in each renderer.js file (for example here, main_window.js)? What am I not understanding here? 解决方案 EditAs another user asked, let me explain my answer below.The proper way to use the preload.js in Electron is to expose whitelisted wrappers around any module your app may need to require.Security-wise, it's dangerous to expose require, or anything you retrieve through the require call in your preload.js (see my comment here for more explanation why). This is especially true if your app loads remote content, which many do.In order to do things right, you need to enable a lot of options on your BrowserWindow as I detail below. Setting these options forces your electron app to communicate via IPC (inter-process communication) and isolates the two environments from each other. Setting up your app like this allows you to validate anything that may be a require'd module in your backend, which is free from the client tampering with it.Below, you will find a brief example of what I speak about and how it can look in your app. If you are starting fresh, I might suggest using secure-electron-template (which I am the author of) that has all of these security best-practices baked in from the get go when building an electron app.This page also has good information on the architecture that's required when using the preload.js to make secure apps.main.jsconst { 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.jsconst { contextBridge, ipcRenderer} = require("electron");// Expose protected methods that allow the renderer process to use// the ipcRenderer without exposing the entire objectcontextBridge.exposeInMainWorld( "api", { send: (channel, data) => { // whitelist channels let validChannels = ["toMain"]; if (validChannels.includes(channel)) { ipcRenderer.send(channel, data); } }, receive: (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.receive("fromMain", (data) => { console.log(`Received ${data} from main process`); }); window.api.send("toMain", "some data"); </script></body></html> 这篇关于如何在Electron中正确使用preload.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-19 15:13