recherche

Maison  >  Questions et réponses  >  le corps du texte

Utiliser correctement preload.js dans Electron : un guide complet

<p>J'ai essayé d'utiliser un module de nœud (dans ce cas <code>fs</code>) dans mon processus <code>renderer</code> <pre class="brush:php;toolbar:false;">// main_window.js const fs = exiger('fs') fonction action() { console.log(fs) }</pré> <p><sup>Remarque : lorsque j'appuie sur le bouton dans <code>main_window</code>, la fonction <code>action</code> </sup></p> <p>Mais cela produit l'erreur : </p> <pre class="brush:php;toolbar:false;">Uncaught ReferenceError : require n'est pas défini sur main_window.js:1</pre> <p>J'ai pu résoudre ce problème, comme le suggère cette réponse acceptée, en ajoutant ces lignes à mon <code>main.js</code> lors de l'initialisation de <code>main_window</code> /p> <pre class="brush:php;toolbar:false;">// main.js main_window = nouveau BrowserWindow ({ largeur : 650, hauteur : 550, Préférences Web : { nodeIntegration : vrai } })</pré> Cependant, selon la documentation, ce n'est pas la meilleure pratique, je devrais créer un fichier <code>preload.js</code> et y charger ces modules Node, puis dans tous mes <code>renderer</ code> Utilisez-le dans le processus.Comme ceci :<p><br /></p> <p><code>main.js</code>:</p> <pre class="brush:php;toolbar:false;">main_window = new BrowserWindow({ largeur : 650, hauteur : 550, Préférences Web : { préchargement : path.join(app.getAppPath(), 'preload.js') } })</pré> <p><code>preload.js</code>:</p> <pre class="brush:php;toolbar:false;">const fs = require('fs') window.test = fonction() { console.log(fs) }</pré> <p><code>main_window.js</code>:</p> <pre class="brush:php;toolbar:false;">fonction action() { fenêtre.test() }</pré> <p>Et ça marche ! </p> <heure /> <p>Maintenant, ma question est la suivante : n'est-il pas contre-intuitif que je doive écrire la plupart du code pour le processus <code>renderer</code> n'avez accès qu'au module Node dans <code>preload.js</code>), puis appelez simplement les fonctions dans chaque fichier <code>renderer.js</code> (comme ici, <code>main_window. js</code>) ? Qu'est-ce que je ne comprends pas ici ? </p>
P粉197639753P粉197639753456 Il y a quelques jours498

répondre à tous(2)je répondrai

  • P粉615829742

    P粉6158297422023-08-28 19:14:20

    Considérez cet exemple

    Tout ce qui figure dans la documentation officielle ne peut pas être implémenté directement n'importe où dans le code. Vous devez avoir une compréhension concise de l’environnement et des processus.

    Environnement/Processus Description
    Principal L'API est plus proche du système d'exploitation (niveau bas). Ceux-ci incluent le système de fichiers, les fenêtres contextuelles de notification basées sur le système d'exploitation, la barre des tâches, etc. Ceux-ci sont implémentés via une combinaison de l'API principale d'Electron et de Node.js
    Préchargé Récente Annexe pour éviter les fuites de la puissante API disponible dans l'environnement principal. Pour plus de détails, consultez le Journal des modifications d'Electron v12< /a> et le Issue #23506.
    Rendu API pour les navigateurs Web modernes tels que DOM et JavaScript frontal (avancé). Ceci est réalisé grâce à Chromium.

    Isolement du contexte et intégration des nœuds

    Scène contextIsolation nodeIntegration Remarques
    A Aucun préchargement requis. Node.js est disponible dans Main mais pas dans Renderer.
    B true Aucun préchargement requis. Node.js est disponible dans Main et Renderer.
    C true Nécessite un préchargement. Node.js est disponible en chargement principal et en préchargement, mais pas en rendu. Par défaut. Recommandé.
    D true true Nécessite un préchargement. Node.js est disponible dans Main, Preload et Renderer.

    Comment utiliser correctement le préchargement ?

    Vous devez utiliser la communication inter-processus (IPC) d'Electron pour que le processus principal et le processus de rendu communiquent.

    1. Dans le processus main, utilisez :
    2. Dans le processus de préchargement, exposez un point de terminaison défini par l'utilisateur au processus de rendu.
    3. Dans le processus renderer, utilisez le point de terminaison défini par l'utilisateur public pour :
      • Envoyer un message à Main
      • Recevoir des messages de Main

    Exemple de mise en œuvre

    Principal

    /**
     * Sending messages to Renderer
     * `window` is an object which is an instance of `BrowserWindow`
     * `data` can be a boolean, number, string, object, or array
     */
    window.webContents.send( 'custom-endpoint', data );
    
    /**
     * Receiving messages from Renderer
     */
    ipcMain.handle( 'custom-endpoint', async ( event, data ) => {
        console.log( data )
    } )
    

    Préchargé

    const { contextBridge, ipcRenderer } = require('electron')
    
    contextBridge.exposeInMainWorld( 'api', {
        send: ( channel, data ) => ipcRenderer.invoke( channel, data ),
        handle: ( channel, callable, event, data ) => ipcRenderer.on( channel, callable( event, data ) )
    } )
    

    Renderer

    /**
     * Sending messages to Main
     * `data` can be a boolean, number, string, object, or array
     */
    api.send( 'custom-endpoint', data )
    
    /**
     * Receiving messages from Main
     */
    api.handle( 'custom-endpoint', ( event, data ) => function( event, data ) {
        console.log( data )
    }, event);
    

    Que diriez-vous d'utiliser Promise ?

    Gardez votre engagement envers le même processus/environnement autant que possible. Vos promesses sur main devraient rester sur main. Votre engagement envers le renderer doit également rester sur le moteur de rendu. Ne vous engagez pas à passer du programme principal au préchargeur puis au moteur de rendu.

    Système de fichiers

    La plupart de votre logique métier doit toujours être du côté principal ou du moteur de rendu, mais elle ne doit jamais être en préchargement. En effet, le préchargement existe presque exclusivement en tant que support. La précharge doit être très faible.

    Dans le cas d'OP , fs fs doit être implémenté côté maître.

    répondre
    0
  • P粉323374878

    P粉3233748782023-08-28 11:18:17

    Modifié 2022


    J'ai publié un article plus volumineux sur l'histoire d'Electron

    (Comment la sécurité a changé dans les versions d'Electron) et d'autres considérations de sécurité que les développeurs d'Electron peuvent prendre pour garantir une utilisation correcte du préchargement dans les nouveaux documents d'applications.

    Modifié 2020

    Comme un autre utilisateur l'a demandé, permettez-moi d'expliquer ma réponse ci-dessous.

    preload.js 的正确方法是在您的应用可能需要 requireExposez un wrapper de liste blanche autour de n'importe quel module utilisant

    dans Electron.

    require 或通过 preload.js 中的 requireDu point de vue de la sécurité, exposer < a href="https://github.com/electron/ Electron/issues/9920#issuecomment-575839738" rel="noreferrer"> tout ce qui est récupéré par un appel est dangereux (voir mon commentaire

    pour plus d'explications). Cela est particulièrement vrai si votre application charge du contenu distant (ce que font de nombreuses applications).

    Pour faire cela correctement, vous devez définir la < 上启用许多选项code>BrowserWindowrequire comme je le détaille ci-dessous. La définition de ces options force votre application Electron à communiquer via IPC (Inter-Process Communication) et isole les deux environnements l'un de l'autre. Configurer votre application de cette manière vous permet de valider tout ce qui dans le backend pourrait être un module require

    sans qu'il soit falsifié par le client.

    Ci-dessous, vous trouverez un court exemple de ce dont je parle et à quoi cela pourrait ressembler dans votre application. Si vous êtes nouveau, je pourrais vous recommander d'utiliser secure-electron-templatesecure-electron-template< /a>

    (dont je suis l'auteur) pour intégrer toutes ces bonnes pratiques de sécurité dès le départ lors de la création d'applications électroniques.

    Cette page

    contient également de bonnes informations sur l'architecture requise lors de l'utilisation de preload.js pour créer des applications sécurisées.

    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

    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>
    

    répondre
    0
  • Annulerrépondre