如何升级到Electron 14+

falq053o  于 2022-12-08  发布在  Electron
关注(0)|答案(1)|浏览(226)

我使用一个开源应用程序Caprine,它的电子版本非常旧(10).由于Electron 10中的一个bug,它甚至无法在我的操作系统上启动(Ubuntu 22.04)。然后,我决定分叉这个项目,并尽我所能将其更新到Electron 13。我合并了一个开放的上游拉取请求,它能够让我升级到Electron 11。从那里,我将过时的shell.moveItemToTrash更改为shell.trashItem,这让我进入了电子13。
现在,由于电子13已经被弃用,甚至不能在Wayland上工作,我认为是时候再次升级了。唯一的问题是,我在远程模块上遇到了麻烦,它已经被移到了用户区。我该如何启用远程模块?

我对JS/TS一无所知。我对C++只有有限的经验。我只是希望Caprine能在我的系统上正常工作,也能帮助其他有类似问题的人。
到目前为止,我已经尝试过:

  1. enableRemoteModule is missing from Electron v14 TypeScript type definitions
  2. https://github.com/electron/electron/issues/21408#issuecomment-564184702
    当我按照这些步骤操作时,应用程序就不运行了。
slsn1g29

slsn1g291#

不幸的是,我没有足够的时间来研究项目源代码或您的fork中的每一个方法调用,但我想说的是 * 一般 *,您需要做的是移动任何npm软件包或操作系统调用(即fs)添加到main进程,而不是renderer进程。我写了一个post,描述了Electron框架是如何变化的。总体而言,最新版本的Electron中的最佳实践是,main进程应该访问操作系统上的任何内容,而渲染器(即视图)只是呈现你的应用程序的UI。在你的UI中有操作系统级的操作是不好的安全明智的。我花了将近两年的时间创建this secure Electron template,今天仍然维护它。(如果旧的Electron应用程序在渲染器进程中大量使用Remote或require模块,则它们可能需要大量投资才能很好地升级到新版本的Electron框架)。
我有一个更具体的例子,说明如何在一个电子应用程序中使用fs而 * 不 * 使用Remote。为了将Caprine移到一个更新的电子框架版本,你必须对渲染器/UI进程中的任何其他require模块进行类似的操作。

主文件.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);
  });
});

预加载.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));
            }
        }
    }
);

索引.html

<!doctype html>
<html lang="en-US">
<head>
    <meta charset="utf-8"/>
    <title>Title</title>
</head>
<body>
    <script>
        // Called when message received from main process
        window.api.receive("fromMain", (data) => {
            console.log(`Received ${data} from main process`);
        });

        // Send a message to the main process
        window.api.send("toMain", "some data");
    </script>
</body>
</html>

相关问题