Методы доступа в основном процессе electron из процесса рендеринга после сборки

#javascript #node.js #electron #electron-forge #node-sqlite3

Вопрос:

Хорошо, у меня есть эти методы в моем index.js основной процесс, к которому я хочу получить доступ из процесса рендеринга. Я попробовал два способа осуществить этот процесс.

ipcMain и ipcRender

Первая идея состояла в том, чтобы использовать ipcMain и ipcRender с помощью «on» и «sendSync». Я получаю сообщение об ошибке «объект не может быть клонирован».

Index.js — Основной процесс

       ipcMain.on( "getData", ( event, callBack ) => {
        db = new sqlite3.Database(
          dbPath,
          sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, 
          function(error) { 
            if(error){
                log.error(`exception: ${error}`);
                //throw error
                if (callBack) callBack(error);
            }
            data.getModel(db, log, function(rawDataStr) {
                if (callBack) callBack(rawDataStr);
            })
          }
        )
        return db
      } );
 

App.Js — Процесс Рендеринга

     window.require('electron').ipcRenderer.sendSync( "getData",function(rawData){
      if (rawData.name amp;amp; rawData.name == 'Error') {
        alert('PRT DB is not present');
      } else {
        sharedObj.rawData = rawData;
        app.advanceReadiness();
      }
    })
 

@электронный/дистанционный

Другим решением, которое я попробовал, было использование @electron/remote. Я понимаю, что удаленный модуль был изношен, но я был готов попробовать его. Это работает, когда я запускаю приложение локально, но как только я создаю приложение с помощью electron-forge, оно больше не может найти мою глобальную переменную.

Index.js — Основной процесс

 require('@electron/remote/main').initialize()
      global.sharedObj = {
        getData:function(callBack){ 
          db = new sqlite3.Database(
            dbPath,
            sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, 
            function(error) { 
              if(error){
                  log.error(`exception: ${error}`);
                  //throw error
                  if (callBack) callBack(error);
              }
              data.getModel(db, log, function(rawDataStr) {
                  if (callBack) callBack(rawDataStr);
              })
            }
          )
        }
      }
 

App.js — Процесс Рендеринга

     var sharedObj = window.require('@electron/remote').getGlobal('sharedObj');
    sharedObj.getData(function (rawData) {
      if (rawData.name amp;amp; rawData.name == 'Error') {
        alert('PRT DB is not present');
      } else {
        sharedObj.rawData = rawData;
        app.advanceReadiness();
      }
    });
 

Комментарии:

1. Я не использовал sqlite с electron, new sqlite3.Database создает ли соединение с базой данных или вы выполняете запрос?

Ответ №1:

Я подозреваю, что ваше соединение с БД невозможно клонировать, потому что этот объект БД не соответствует одному из допустимых значений, которые могут быть сериализованы с помощью IPC (межпроцессная связь). (Смотрите этот раздел, чтобы узнать, что мы можем передать между рендерером > основным процессом без проблем).

Вам, вероятно, нужно сделать что-то подобное. Я не знаком с использованием sqlite3 в JS, но, надеюсь, это поможет вам начать на правильном пути. Общая суть заключается в том, что вы должны хранить ссылку на свою базу данных в своем main.js файл, а затем настройте прослушиватель, который будет прослушивать запросы с вашей начальной страницы. Как только сообщение будет отправлено на main.js файл (т. е. серверная часть), вы запросите свою базу данных, а затем вернете результаты на внешний интерфейс, отправив сообщение IPC обратно ( win.webContents.send("fromMain", data); в примере elow).

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;
let db = new sqlite3.Database(
    dbPath,
    sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
    function (error) {
        if (error) {
            log.error(`exception: ${error}`);
            //throw error
            if (callBack) callBack(error);
        }
        data.getModel(db, log, function (rawDataStr) {
            if (callBack) callBack(rawDataStr);
        })
    }
);

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) => {
    db.retrieveData().then(data => {

        // Send result back to renderer process
        win.webContents.send("fromMain", data);
    });
});
 

preload.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

 <!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>