我正在为自己的目的创建一个电子应用程序。我的问题是,当我在我的HTML页面内使用节点函数时,它抛出了一个错误:

'require()'没有定义。

是否有办法在所有HTML页面中使用Node功能?如果有可能,请给我一个如何做到这一点的例子或提供一个链接。下面是我试图在我的HTML页面中使用的变量:

  var app = require('electron').remote; 
  var dialog = app.dialog;
  var fs = require('fs');

这些是我在电子中所有HTML窗口中使用的值。


当前回答

你必须在webPreferences中启用nodeIntegration才能使用它。见下文,

const { BrowserWindow } = require('electron')
let win = new BrowserWindow({
  webPreferences: {
    nodeIntegration: true
  }
})
win.show()

在电子5.0中有一个突破性的api变化(关于存储库的公告)。在最近的版本中,nodeIntegration默认设置为false。

由于Node.js集成了Electron, DOM中插入了一些额外的符号,如module, exports, require。这给一些库带来了问题,因为它们想要插入具有相同名称的符号。要解决这个问题,你可以在Electron中关闭节点集成:

但是如果你想保留使用Node.js和Electron api的能力,你必须在包含其他库之前重命名页面中的符号:

<head>
    <script>
        window.nodeRequire = require;
        delete window.require;
        delete window.exports;
        delete window.module;
    </script>
    <script type="text/javascript" src="jquery.js"></script>
</head>

其他回答

你是否在BrowserWindow初始化时使用nodeIntegration: false ?如果是,设置为true(默认值为true)。

并且像这样在HTML中包含你的外部脚本(而不是<script> src="./index.js" </script>):

<script>
   require('./index.js')
</script>

首先,@Sathiraumesh解决方案给电子应用程序留下了巨大的安全问题。想象一下,你的应用程序正在为messenger.com添加一些额外的功能,例如,当你有未读消息时,工具栏的图标会改变或闪烁。所以在你的main.js文件中,你像这样创建新的BrowserWindow(注意我故意拼错了messenger.com):

app.on('ready', () => {
    const mainWindow = new BrowserWindow({
        webPreferences: {
            nodeIntegration: true
        }
    });
    mainWindow.loadURL(`https://messengre.com`);
});

如果messengre.com是一个恶意网站,想要伤害你的电脑怎么办?如果你设置了nodeIntegration: true,这个站点可以访问你的本地文件系统,并且可以执行以下命令:

require('child_process').exec('rm -r ~/');

您的主目录消失了。

解决方案 只暴露你需要的,而不是一切。这是通过使用require语句预加载javascript代码来实现的。

// main.js
app.on('ready', () => {
    const mainWindow = new BrowserWindow({
        webPreferences: {
            preload: `${__dirname}/preload.js`
        }
    });
    mainWindow.loadURL(`https://messengre.com`);
});
// preload.js
window.ipcRenderer = require('electron').ipcRenderer;
// index.html
<script>
    window.ipcRenderer.send('channel', data);
</script>

现在糟糕的messengre.com不能删除你的整个文件系统。

看起来Electron的安全性是这样进化的(来源)。

Electron 1 nodeIntegration默认为true

Renderer可以完全访问Node API—如果Renderer加载远程代码,则存在巨大的安全风险。

Electron 5 nodeIntegration默认为false

当设置为false时,将使用预加载脚本向Renderer公开特定的API。(不管nodeIntegration的值如何,预加载脚本总是可以访问Node api)

//preload.js
window.api = {
    deleteFile: f => require('fs').unlink(f)
}

Electron 5 contextIsolation默认为true(实际上在Electron 11中仍然默认为false)

这将导致预加载脚本在单独的上下文中运行。你不能再做窗户了。API = ....你现在要做的是:

//preload.js
const { contextBridge } = require('electron')

contextBridge.exposeInMainWorld('api', {
    deleteFile: f => require('fs').unlink(f)
})

电子6 require()节点内置沙盒渲染器不再隐式加载远程版本

如果Renderer有沙盒设置为true,你必须做:

//preload.js
const { contextBridge, remote } = require('electron')

contextBridge.exposeInMainWorld('api', {
    deleteFile: f => remote.require('fs').unlink(f)
})

Electron 10 enableRemoteModule默认为false(远程模块在Electron 12中已弃用)

remote模块用于当你需要从沙盒渲染器中访问Node api时(如上面的例子);或者当你需要访问仅对主进程可用的电子api时(如对话框,菜单)。如果没有remote,您需要编写如下所示的显式IPC处理程序。

//preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('api', {
    displayMessage: text => ipcRenderer.invoke("displayMessage", text)
})

//main.js
const { ipcMain, dialog } = require('electron')

ipcMain.handle("displayMessage", text => dialog.showMessageBox(text))

Electron 10弃用节点集成标志(在Electron 12中删除)

建议

总是设置{nodeIntegration: false, contextIsolation: true, enableRemoteModule: false}。

为了最大的安全性,设置{sandbox: true}。您的预加载脚本将必须使用IPC调用主进程来完成所有工作。

如果sandbox为false,你的预加载脚本可以直接访问Node API,如require('fs'). readfile。你是安全的,只要你不这样做

//bad
contextBridge.exposeInMainWorld('api', {
    readFile: require('fs').readFile
})

你必须在webPreferences中启用nodeIntegration才能使用它。见下文,

const { BrowserWindow } = require('electron')
let win = new BrowserWindow({
  webPreferences: {
    nodeIntegration: true
  }
})
win.show()

在电子5.0中有一个突破性的api变化(关于存储库的公告)。在最近的版本中,nodeIntegration默认设置为false。

由于Node.js集成了Electron, DOM中插入了一些额外的符号,如module, exports, require。这给一些库带来了问题,因为它们想要插入具有相同名称的符号。要解决这个问题,你可以在Electron中关闭节点集成:

但是如果你想保留使用Node.js和Electron api的能力,你必须在包含其他库之前重命名页面中的符号:

<head>
    <script>
        window.nodeRequire = require;
        delete window.require;
        delete window.exports;
        delete window.module;
    </script>
    <script type="text/javascript" src="jquery.js"></script>
</head>

出于安全原因,你应该保持nodeIntegration: false,并使用一个预加载脚本,通过窗口变量将你所需要的从Node/Electron API暴露给渲染器进程(视图)。来自电子文档:

预加载脚本继续可以访问require和其他Node.js特性


例子

main.js

const mainWindow = new BrowserWindow({
  webPreferences: {
    preload: path.join(app.getAppPath(), 'preload.js')
  }
})

preload.js

const { remote } = require('electron');

let currWindow = remote.BrowserWindow.getFocusedWindow();

window.closeCurrentWindow = function(){
  currWindow.close();
}

renderer.js

let closebtn = document.getElementById('closebtn');

closebtn.addEventListener('click', (e) => {
  e.preventDefault();
  window.closeCurrentWindow();
});