Javascript 电子 require() 未定义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44391448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:29:34  来源:igfitidea点击:

Electron require() is not defined

javascripthtmlnode.jselectron

提问by Mari Selvan

I'm creating an Electron app for my own purpose. My problem is when I'm using node functions inside my HTML page it throws an error of:

我正在为自己的目的创建一个 Electron 应用程序。我的问题是,当我在 HTML 页面中使用节点函数时,它会引发以下错误:

'require()' is not defined.

'require()' 未定义。

Is there any way to use Node functionalities in all my HTML pages? If it is possible please give me an example of how to do this or provide a link. Here are the variables I'm trying to use in my HTML page:

有没有办法在我的所有 HTML 页面中使用 Node 功能?如果可能,请给我一个如何执行此操作的示例或提供链接。以下是我尝试在 HTML 页面中使用的变量:

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

and these are the values I'm using in all my HTML windows within Electron.

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

回答by Sathiraumesh

As of version 5, the default for nodeIntegrationchanged from true to false. You can enable it when creating the Browser Window:

从第 5 版开始,默认值nodeIntegration从 true 更改为 false。您可以在创建浏览器窗口时启用它:

app.on('ready', () => {
    mainWindow = new BrowserWindow({
        webPreferences: {
            nodeIntegration: true
        }
    });
});

回答by Rafael Croffi

For security reasons, you should keep nodeIntegration: falseand use a preload script to expose just what you need from Node/Electron API to the renderer process (view) via window variable. From the Electron docs:

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

Preload scripts continue to have access to requireand other Node.js features

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



Example

例子

main.js

主文件

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

preload.js

预加载.js

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

let currWindow = remote.BrowserWindow.getFocusedWindow();

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

renderer.js

渲染器.js

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

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

回答by Zac

I hope this answer gets some attention, because a large majorityof answers here leave largesecurity holes in your electron app. In fact this answeris essentially what you should be doing to use require()in your electron apps. (There is just a new electron API that makes it a little bit cleaner in v7).

我希望这个答案得到一些关注,因为这里的大部分答案都会在您的电子应用程序中留下很大的安全漏洞。事实上,这个答案本质上就是你应该require()在你的电子应用程序中使用的东西。(只有一个新的电子 API 使它在 v7 中更简洁一些)。

I wrote a detailed explanation/solutionin github using the most current electron apis of how you can require()something, but I'll explain briefly here why you should follow an approach using a preload script, contextBridge and ipc.

我使用最新的电子 API 在 github 中写了一个详细的解释/解决方案require(),但我将在这里简要解释为什么你应该遵循使用预加载脚本、contextBridge 和 ipc 的方法。

The problem

问题

Electron apps are great because we get to use node, but this power is a double-edged sword. If we are not careful, we give someone access to node through our app, and with node a bad actor can corrupt your machine or delete your operating system files (among other things, I imagine).

Electron 应用程序很棒,因为我们可以使用 node,但这种能力是一把双刃剑。如果我们不小心,我们会通过我们的应用程序让某人访问 node,并且使用 node 的坏人可能会损坏您的机器或删除您的操作系统文件(我想还有其他事情)。

As brought up by @raddevus in a comment, this is necessarywhen loading remotecontent. If your electron app is entirely offline/local, then you are probably okay simply turning on nodeIntegration:true. I still would, however, opt to keep nodeIntegration:falseto act as a safeguard for accidental/malicious users using your app, and prevent any possible malware that might ever get installed on your machine from interacting with your electron app and using the nodeIntegration:trueattack vector (incredibly rare, but could happen)!

正如@raddevus 在评论中提出的,这在加载远程内容时是必要的。如果您的电子应用程序完全离线/本地,那么您可能只需打开即可。但是,我仍然会选择继续为使用您的应用程序的意外/恶意用户提供保护,并防止任何可能安装在您机器上的恶意软件与您的电子应用程序交互并使用攻击向量(非常罕见) ,但可能会发生)!nodeIntegration:truenodeIntegration:falsenodeIntegration:true

What does the problem look like

问题是什么

This problem manifests when you (any one of the below):

当您(以下任何一项)时,就会出现此问题:

  1. Have nodeIntegration:trueenabled
  2. Use the remotemodule
  1. nodeIntegration:true启用
  2. 使用remote模块

All of these problems give uninterruptedaccess to node from your renderer process. If your renderer process is ever hiHymaned, you can consider all is lost.

所有这些问题都使您可以从渲染器进程不间断地访问节点。如果您的渲染器进程被劫持,您可以认为一切都已丢失。

What our solution is

我们的解决方案是什么

The solution is to not give the renderer directaccess to node (ie. require()), but to give our electron main process access to require, and anytime our renderer process needs to use require, marshal a request to the main process.

解决方案是不让渲染器直接访问节点(即require()),而是让我们的电子主进程访问require,并且在我们的渲染器进程需要使用的任何时候require,将请求编组到主进程。

The way this works in the latest versions (7+) of Electron is on the renderer side we set up ipcRendererbindings, and on the main side we set up ipcMainbindings. In the ipcMain bindings we set up listener methods that use modules we require(). This is fine and well because our main process can requireall it wants.

在最新版本(7+)Electron 中的工作方式是在渲染器端我们设置ipcRenderer绑定,在主端我们设置ipcMain绑定。在 ipcMain 绑定中,我们设置了使用模块的侦听器方法require()。这很好,因为我们的主进程可以require随心所欲。

We use the contextBridgeto pass the ipcRenderer bindings to our app code (to use), and so when our app needs to use the required modules in main, it sends a message via IPC (inter-process-communication) and the main process runs some code, and we then send a message back with our result.

我们使用contextBridge将 ipcRenderer 绑定传递给我们的应用程序代码(使用),因此当我们的应用程序需要使用requiremain 中的d 模块时,它通过 IPC(进程间通信)发送消息并运行主进程一些代码,然后我们发送一条带有结果的消息。

Roughly, here's what you want to do.

粗略地说,这就是你想要做的。

main.js

主文件

const {
  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.js

预加载.js

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

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.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

索引.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>

Disclaimer

免责声明

I'm the author of secure-electron-template, a secure template to build electron apps. I care about this topic, and have been working on this for a few weeks (at this point in time).

我是secure-electron-template构建电子应用程序的安全模板的作者。我关心这个话题,并且已经为此工作了几个星期(此时此刻)。

回答by RoyalBingBong

Are you using nodeIntegration: falsewhile BrowserWindow initialization? If so, set it to true(defaults value is true).

你在使用nodeIntegration: falsewhile BrowserWindow 初始化吗?如果是,请将其设置为true(默认值为true)。

And include your external scripts in the HTML like this (not as <script> src="./index.js" </script>):

并将您的外部脚本包含在 HTML 中,如下所示(不是 as <script> src="./index.js" </script>):

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

回答by Legolando

First off, @Sathiraumesh solution leaves your electron application with huge security issue. Imagine that your app is adding some extra features to messenger.com, for example toolbar's icon will change or blink when you've have unread message. So in your main.jsfile, you create new BrowserWindow like so (notice I intentionally misspelled messenger.com):

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

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

What if messengre.comis a malicious website, that wants to harm your computer. If you set nodeIntegration: truethis site has access to your local file system and can execute this:

如果messengre.com是一个恶意网站,想要损害您的计算机怎么办。如果您设置nodeIntegration: true此站点可以访问您的本地文件系统并可以执行以下操作:

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

And your home directory is gone.

你的主目录不见了。

Solution
Expose only what you need, instead of everything. This is achived by preloading javascript code with requirestatements.

解决方案
只公开你需要的东西,而不是一切。这是通过使用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>

Now awful messengre.comcannot delete your entire file system.

现在可怕的messengre.com无法删除您的整个文件系统。

回答by Kiran Maniya

You have to enable the nodeIntegrationin webPreferencesto use it. see below,

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

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

There was a breaking api changes in electron 5.0(Announcement on Repository). In recent versions nodeIntegrationis by default set to false.

在电子 5.0(关于存储库的公告)中有一个重大的 api 更改。在最近的版本中nodeIntegration默认设置为false

DocsDue to the Node.js integration of Electron, there are some extra symbols inserted into the DOM like module, exports, require. This causes problems for some libraries since they want to insert the symbols with the same names.To solve this, you can turn off node integration in Electron:

文档由于 Node.js 与 Electron 的集成,DOM 中插入了一些额外的符号,如模块、导出、要求。这会导致一些库出现问题,因为他们想要插入具有相同名称的符号。要解决这个问题,您可以在 Electron 中关闭节点集成:

But if you want to keep the abilities to use Node.js and Electron APIs, you have to rename the symbols in the page before including other libraries:

但是如果你想保留使用 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>

回答by Mari Selvan

Finally, I made it work.Add this code to your HTML document Script Element.

最后,我成功了。将此代码添加到您的 HTML 文档脚本元素中。

Sorry for the late Reply.I use the below code to do this thing.

抱歉回复晚了。我使用下面的代码来做这件事。

window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;

And use nodeRequireinstead of using require.

并使用nodeRequire而不是使用require.

It works Fine.

它工作正常。