如何跨多个文件组织Electron.js渲染器代码而不损害安全性?

sxpgvts3  于 2023-03-16  发布在  Electron
关注(0)|答案(1)|浏览(170)

我正在构建一个Electron.js应用程序,我已经阅读了关于上下文隔离、主进程和渲染器进程等方面的文档。
我很难理解如何在不使用其他框架(如Angular或Vue)的情况下将渲染器进程代码组织到多个文件或类中。
通过将sandbox选项设置为false,我或多或少地实现了这个目标,这允许我将require用于不属于Electron的外部模块。然而,据我所知,这不是一个最佳实践,因为它会带来安全风险。此外,在使用此选项时,我遇到了类方面的困难。* 只有函数才能正常工作。*
下面是给我错误的代码。我怎样才能把我的渲染器代码组织成多个文件而不发疯呢?

主文件.js

const { app, BrowserWindow, dialog, ipcMain } = require('electron');
const nodePath = require("path");

function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      sandbox: false,
      nodeIntegration: false,
      contextIsolation: true,
      preload: nodePath.join(__dirname, 'preload.js')
    }
  });

  win.loadFile('index.html');
}

ipcMain.handle('open-dialog', async (event, arg) => {
  const result = await dialog.showOpenDialog({
    properties: ['openFile', 'multiSelections']
  });

  return result;
});

app.whenReady().then(() => {
  createWindow();

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

预加载.js

const { contextBridge, ipcRenderer } = require('electron');
const Test = require('./test');

contextBridge.exposeInMainWorld('myAPI', {
    Test: Test
});

渲染器.js

const api = window.myAPI;

const button = document.querySelector('#hi');
button.addEventListener('click', async () => {
    const test = new api.Test();
    test.hi();
});

test.js*存放要导出的函数或类的文件 *

class Test {
    constructor() {
        this.name = "TheSmith1222";
    }
    hi(){
        console.log("Hi, " + this.name);
    }
}

module.exports = {
  Test
};

索引.html

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Security-Policy" content="default-src 'self';">
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    <button id="hi">Hi</button>
    <script src="./renderer.js" type="module"></script>
  </body>
</html>

点击输出按钮:

renderer.js:5 Uncaught (in promise) TypeError: api.Test is not a constructor
    at HTMLButtonElement.<anonymous> (renderer.js:5:15)
daolsyd0

daolsyd01#

在组织/加载其他渲染进程脚本时,不需要使用preload.js脚本。
我发现用一个renderer.js文件(通过<script>标签加载到html文件中)管理不同类型的导入,即类和方法文件,也就是说,我相信如果你喜欢,你可以用其他方法来构造它。
我已经包括下面列出的5个文件的代码:

  • main.js(主进程)
  • index.html(渲染过程)
  • renderer.js(渲染进程)
  • test-1.js(渲染进程)
  • test-2.js(渲染进程)

我已经排除了您的preload.js脚本作为其内容和一般实现不影响这个问题。
main.js(主流程)
一个最小的实现来让事情正常工作。

// Import required electron modules
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;

// Import required Node modules
const nodePath = require('path');

// Prevent garbage collection
let window;

function createWindow() {
    const window = new electronBrowserWindow({
        x: 0,
        y: 0,
        width: 800,
        height: 600,
        show: false,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            sandbox: true,
            preload: nodePath.join(__dirname, 'preload.js')
        }
    });

    window.loadFile('index.html')
        .then(() => { window.show(); });

    return window;
}

electronApp.on('ready', () => {
    window = createWindow();
});

electronApp.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        electronApp.quit();
    }
});

electronApp.on('activate', () => {
    if (electronBrowserWindow.getAllWindows().length === 0) {
        createWindow();
    }
});

index.html(渲染进程)
用于测试目的。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Electron Test</title>
        <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
    </head>

    <body>
        <h1>Hello World!</h1>
        <button id="hi-1">Hi (Class)</button>
        <button id="hi-2">Hi (Function)</button>
    </body>

    <script type="module" src="./renderer.js"></script>
</html>

renderer.js(渲染进程)
导入不同的呈现支持文件以供html页使用。

import {Test1} from './test-1.js'; // Class
import {test_2_hi} from './test-2.js'; // Method(s)

const test_1 = new Test1();

document.getElementById('hi-1').addEventListener('click', () => {
    test_1.hi();
})

document.getElementById('hi-2').addEventListener('click', () => {
    test_2_hi();
})

test-1.js(渲染进程)
类的使用。

class Test1 {
    constructor() {
        this.name = 'Test 1 (Class)';
    }

    hi() {
        console.log('Hi from ' + this.name);
    }
}

export {Test1};

test-2.js(渲染进程)
使用标准功能。

let name = 'Test 2 (Function)';

function test_2_hi() {
    console.log('Hi from ' + name);
}

export {test_2_hi};

相关问题