【问题标题】:Electron "require is not defined"电子“要求未定义”
【发布时间】:2019-06-29 20:50:55
【问题描述】:

我正在制作一个需要访问文件系统 (fs) 模块的应用程序,但是即使启用了nodeIntegration,渲染器也会给我这个错误:

Uncaught ReferenceError: require is not defined

我能找到的所有类似问题都有一个解决方案,说他们需要打开nodeIntegration,但我已经启用了它。

这是我的 main.js:

const electron = require('electron');   
const {app, BrowserWindow} = electron;  

let win;

app.on('ready', () => {
    var { width, height } = electron.screen.getPrimaryDisplay().workAreaSize;
    width = 1600;
    height = 900;
    win = new BrowserWindow({'minHeight': 850, 'minWidth': 1600, width, height, webPreferences: {
        contextIsolation: true,
        webSecurity: true,
        nodeIntegration: true
    }});
    win.setMenu(null);
    win.loadFile('index.html');
    win.webContents.openDevTools()
});

我的 index.js,在 index.html 中链接为 <script src="index.js"></script>,目前只有 require("fs");,我已经注释掉了所有其他内容。

我不知道为什么即使启用了nodeIntegration,require 仍然不起作用。

【问题讨论】:

    标签: javascript html node.js electron


    【解决方案1】:

    当您禁用nodeIntegration 但未使用contextIsolation 时,您可以使用预加载脚本在全局对象上公开它的安全版本。 (注意:您不应该将整个 fs 模块暴露给远程页面!)

    这是一个以这种方式使用预加载脚本的示例:

    // main process script
    const mainWindow = new BrowserWindow({
      webPreferences: {
        contextIsolation: false,
        nodeIntegration: false,
        preload: './preload.js'
      }
    })
    
    mainWindow.loadURL('my-safe-file.html')
    
    
    
    // preload.js
    const { readFileSync } = require('fs')
    
    // the host page will have access to `window.readConfig`,
    // but not direct access to `readFileSync`
    window.readConfig = function () {
      const data = readFileSync('./config.json')
      return data
    }
    
    
    
    // renderer.js
    const config = window.readConfig()
    

    如果您只加载本地页面,并且这些页面不加载或执行不安全的动态内容,那么您可能重新考虑在此策略中使用contextIsolation。但是,如果您想保持contextIsolation 处于打开状态(如果您有机会显示不安全的内容,您肯定应该这样做),您只能使用message passing via postMessage 与预加载脚本通信。

    以下是上述相同场景的示例,但启用了 contextIsolation 并使用消息传递。

    // main process script
    const mainWindow = new BrowserWindow({
      webPreferences: {
        contextIsolation: true,
        nodeIntegration: false,
        preload: './preload.js'
      }
    })
    
    mainWindow.loadURL('my-unsafe-file.html')
    
    
    
    // preload.js
    const { readFileSync } = require('fs')
    
    const readConfig = function () {
      const data = readFileSync('./config.json')
      return data
    }
    
    window.addEventListener('message', (event) => {
      if (event.source !== window) return
      if (event.data.type === 'request') {
        window.postMessage({ type: 'response', content: readConfig() })
      }
    })
    
    
    
    // renderer.js
    window.addEventListener('message', (event) => {
      if (event.source !== window) return
      if (event.data.type === 'response') {
        const config = event.data.content
      }
    })
    window.postMessage('request')
    

    虽然这肯定更冗长且难以处理(并迫使事情异步,因为消息传递是异步的),但它也更安全。 postMessage API 周围的一对小型 JS 包装器可以使这更容易使用(例如,通过类似 RPC 的机制),但请记住,使用 contextIsolation 的全部意义在于你不能信任渲染器,因此您的预加载脚本不应只信任它通过postMessage API 获得的任何消息——您应始终验证您收到的事件以确保您信任它。

    This slide deck 详细描述了为什么在不使用上下文隔离的情况下关闭节点集成并不总是一个好主意。

    【讨论】:

    • contextIsolation: true 不会阻止在页面/渲染器中读取 window.readConfig 吗?
    • @ford04 你是对的——我相信不久前有一个错误允许用contextIsolation 修改window。我已经更新了我的答案,使其更加全面。
    • 正如@ford04 所建议的那样,此答案中的第一个示例需要contextIsolation: false 才能工作。
    猜你喜欢
    • 2017-12-28
    • 2019-10-11
    • 2020-10-22
    • 2019-08-01
    • 1970-01-01
    • 2020-04-26
    • 1970-01-01
    • 2019-08-09
    • 2020-07-19
    相关资源
    最近更新 更多