Electron: Error al importar electrones en react | importar {ipcRenderer} desde 'electron'

Creado en 3 jul. 2017  ·  65Comentarios  ·  Fuente: electron/electron

He creado una aplicación simple de reacción con create-react-app y la he integrado con electron con éxito. Todo funcionaba muy bien hasta que intenté importar un electrón dentro del archivo del creador de acciones. Si elimino la línea de abajo, la aplicación funciona bien. El problema es que no puedo usar el ipcRenderer para comunicarme desde el lado de reacción al proceso principal de electrones.

Esta línea hace que la aplicación se bloquee:
import { ipcRenderer } from 'electron';

Obtuve el siguiente error:

TypeError: fs.existsSync no es una función
(función anónima)
node_modules / electron / index.js: 6

  3 | 
  4 | var pathFile = path.join(__dirname, 'path.txt')
  5 | 
> 6 | if (fs.existsSync(pathFile)) {
  7 |   module.exports = path.join(__dirname, fs.readFileSync(pathFile, 'utf-8'))
  8 | } else {
  9 |   throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')

Descubrí en Google que este es un problema común al intentar importar electrón.

Gracias por la ayuda

Comentario más útil

@MarshallOfSound es mi error.

Encontré la solución en el problema # 7300 si puede ayudar a alguien.

const { ipcRenderer } = window.require('electron');

Tenga en cuenta que esto funcionará cuando ejecute la aplicación Electron, pero si solo desea probar su código React dentro del navegador, aún se bloqueará (window.require no está definido en el navegador como lo está en Electron).

Todos 65 comentarios

CRA usa un paquete web que interfiere con la carga de módulos estándar (incluido fs).

Recomiendo buscar en el modo Electron para webpack y expulsarlo de CRA

Los problemas de GitHub son para solicitudes de funciones e informes de errores, las preguntas sobre el uso de Electron deben dirigirse a la comunidad o al Canal Slack .

@MarshallOfSound es mi error.

Encontré la solución en el problema # 7300 si puede ayudar a alguien.

const { ipcRenderer } = window.require('electron');

Tenga en cuenta que esto funcionará cuando ejecute la aplicación Electron, pero si solo desea probar su código React dentro del navegador, aún se bloqueará (window.require no está definido en el navegador como lo está en Electron).

Si desea acceder a app.quit (), puede usar esto:

const {aplicación} = window.require ('electron'). remote;

Quizás ayude a alguien ...

@CiriousJoker estas son soluciones, ¡gracias!

Sigo recibiendo window.require is not a function . Estoy usando Electron con React Starter Kit (https://github.com/kriasoft/react-starter-kit). Todo está funcionando bien, excepto esto.

Configuré mi aplicación Electron para cargar mi aplicación desde la web, por lo que la aplicación no se ejecuta localmente:
https://gist.github.com/holgersindbaek/68f6db82f507967a51ca75c527faeff6

Lo que estoy tratando de hacer es llamar a ipcRenderer en uno de mis archivos de React. Sin embargo, no estoy seguro de si es posible cuando mi aplicación se carga desde la web. ¿Alguna sugerencia?

@holgersindbaek

En el mismo barco que tú ... ¿Encontraste una solución?

No. Estoy bastante seguro de que no es posible cargar ipcRenderer desde el navegador.

Si está ejecutando su aplicación React en el navegador, no funcionará. Ejecútelo dentro de Electron y debería estar bien.

@Amthieu Gracias por el consejo. Todavía tengo dudas sobre cómo puedo hacer que mi proyecto React (basado en React Starter Kit) se ejecute en Electron. Cualquier consejo sería muy apreciado:

https://discuss.atom.io/t/getting-electron-to-work-with-react-starter-kit/48594

Bien, tengo una solución.

1) Crea un preload.js file con el código:

window.ipcRenderer = require('electron').ipcRenderer;

2) Precargue este archivo en su main.js a través de webPreferences :

  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      preload: __dirname + '/preload.js'
    }
  });

3) Ahora, tendrá acceso desde su aplicación de reacción. Por ejemplo, esto funcionará:

componentDidMount() {
        if (isElectron()) {
            console.log(window.ipcRenderer);
            window.ipcRenderer.on('pong', (event, arg) => {
                this.setState({ipc: true})
            })
            window.ipcRenderer.send('ping')
        }
    }

Nota: usando esto: https://github.com/cheton/is-electron para la función isElectron()

@HemalR El paso 3 debería ser el siguiente (ahora):

componentDidMount() {
    if (window.isElectron) {
        console.log(window.ipcRenderer);
        window.ipcRenderer.on('pong', (event, arg) => {
            this.setState({ipc: true})
        })
        window.ipcRenderer.send('ping')
    }
}

Nota : window.isElectron no es una función.

@ nparsons08

Disculpas: debería haber agregado de dónde obtengo esElectron, haber editado mi ejemplo de código con el enlace a: https://github.com/cheton/is-electron

@holgersindbaek
¿Hay una solución ahora?

para mí solo funciona si nodeIntegration es true ;

webPreferences: {
      nodeIntegration: true, 
      preload: __dirname + '/preload.js'
}

¡ Funciona muy bien con la solución

ahora ¿CÓMO enviar DE un electrón a reaccionar?

intentado con
en el lado de los electrones

 ipcMain.emit("pong", "Hello!"); 

pero no se recibió nada del oyente de React

window.ipcRenderer.on("pong", (event, arg) => {
        console.log("PONG");
});

¿Es correcto usar ipcMain.emit () o debería usar algo más?

ok, acabo de descubrir que tengo que usar (en el proceso principal de electrones)

mainWindow.webContents.send("pong", "Hello!");

¡gracias a todos!

Intenté todo lo anterior sin éxito. Lo que funcionó para mí fue un truco gigante. Modifique el archivo ./node_modules/electron/index.js y codifique la ruta a electron.exe

p.ej

function getElectronPath() {
  return 'D:\\Repos\\MyProject\\node_modules\\electron\\dist\\electron.exe';
}

module.exports = getElectronPath();

Vaya, no pude hacer que el IPCRenderer funcionara en mis componentes React. Probé todo el método anterior. ¿Alguno de ustedes, por cierto, tuvo alguna pista que pueda usar para que funcione? Gracias

Hmmm ... Mi aplicación de electrones todavía funciona bien con mi solución anterior, pero no la he actualizado en unos meses (no era necesario).

Me pregunto si hay un cambio radical que impida que esto funcione. ¿Quizás ustedes puedan publicar sus versiones electrónicas?

@cyclonstep ¿

Estoy usando el paquete para empaquetar.
Window.require también lo resolvió para mí (también muestra, lo que no):

importar Vue desde 'vue / dist / vue.min'
importar la aplicación desde './App'

// ¿MALO? importar {ipcRenderer} desde 'electron'
// ¿MALO? const {ipcRenderer} = require ('electron')
// BIEN:
const {ipcRenderer} = window.require ('electron')

(más abajo en el mismo archivo está el electrón "pong-Demo" , que prueba un poco que funciona)

Quizás digno de mención: incluso cuando se hace mal, el tamaño del paquete no crece (comparado con sin el requerimiento de electrones. Esta es hasta ahora mi primera y hasta ahora única importación de electrones del lado de procesamiento) por todo el tamaño del electrón o algo así, pero solo alrededor de 20kb , que parece ser un código shim / wrapper por sí solo, proveniente de node_modules/electron-download/node_modules/debug/dist/debug.js : 242: ff ...

2: [function (require, module, exports) {
  // shim for using process in browser
  var process = module.exports = {}; // cached from whatever global is present so that test runners that
 stub it

De todos modos, las cosas funcionan como se dijo anteriormente.

Nodo versión 10.2.0
Versión de Chrome 66.0.3359.181
Electron versión 3.0.2

window.require no me funcionaba en mi secuencia de comandos principal con el error window is not defined , así que cambié a const electron = eval('require')("electron") . Espero que esto ayude a alguien. Usando webpack, y el problema era que webpack estaba evaluando mi declaración de requerimiento en el momento de la compilación.

@MarshallOfSound es mi error.

Encontré la solución en el problema # 7300 si puede ayudar a alguien.

const { ipcRenderer } = window.require('electron');

Tenga en cuenta que esto funcionará cuando ejecute la aplicación Electron, pero si solo desea probar su código React dentro del navegador, aún se bloqueará (window.require no está definido en el navegador como lo está en Electron).

Y para mecanografiado:

import {IpcRenderer} from 'electron';

declare global {
  interface Window {
    require: (module: 'electron') => {
      ipcRenderer: IpcRenderer
    };
  }
}

const { ipcRenderer } = window.require('electron');

@moshfeu Su solución funciona de

Para mecanografiar y usar el ejemplo de @HemalR de arriba pero SIN nodeIntegration: true : https://github.com/electron/electron/issues/9920#issuecomment -336757899:

Bien, tengo una solución.

  1. Crea un preload.js file con el código:
window.ipcRenderer = require('electron').ipcRenderer;
  1. Precargue este archivo en su main.js a través de webPreferences :
  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      preload: __dirname + '/preload.js'
    }
  });
  1. Ahora, tendrá acceso desde su aplicación de reacción. Por ejemplo, esto funcionará:
componentDidMount() {
      if (isElectron()) {
          console.log(window.ipcRenderer);
          window.ipcRenderer.on('pong', (event, arg) => {
              this.setState({ipc: true})
          })
          window.ipcRenderer.send('ping')
      }
  }

Nota: usando esto: https://github.com/cheton/is-electron para la función isElectron()

combinado con
https://github.com/electron/electron/issues/9920#issuecomment -447157348

Usé esto:

import { IpcRenderer } from 'electron';

declare global {
  interface Window {
    ipcRenderer: IpcRenderer
  }
}

export const { ipcRenderer } = window;

¡Espero que ayude a alguien! Funciona con stenciljs, e imagino reaccionar y angular

simplemente agregue target: "electron-renderer" en las configuraciones del paquete web.
exportar predeterminado {
...
objetivo: "renderizador de electrones"
...
}

Hola, uso CRA + Electron. Y construyo mi proyecto por objetivo 'renderizador de electrones'. Funciona bien al cargar archivos en la carpeta de compilación, pero arroja un error cuando desarrollo y cargo la URL localhost:3000 . Supongo que la razón es que utilizo la API de nodo y la API de electrones en los componentes de reacción. ¿Alguien tiene la solución? Gracias.

TypeError: fs.existsSync is not a function

Sí, la fs api no está disponible en el navegador. Si entiendo la situación correctamente, ejecuta su aplicación usando react-scripts start (que es el script predeterminado de npm start en CRA).

La forma correcta de hacer esto es ejecutar electron . . Puede verlo en los documentos: https://electronjs.org/docs/tutorial/first-app.

LMK si funciona para usted. También puede ver cómo funciona en mi aplicación: https://github.com/moshfeu/y2mp3 (tenga en cuenta que no se creó con CRA)

Hola, uso CRA + Electron. Y construyo mi proyecto por objetivo 'renderizador de electrones'. Funciona bien al cargar archivos en la carpeta de compilación, pero arroja un error cuando desarrollo y cargo la URL localhost:3000 . Supongo que la razón es que utilizo la API de nodo y la API de electrones en los componentes de reacción. ¿Alguien tiene la solución? Gracias.

TypeError: fs.existsSync is not a function

simplemente agregue target: "electron-renderer" en las configuraciones del paquete web.
exportar predeterminado {
...
objetivo: "renderizador de electrones"
...
}

A mí también me funciona.

Aquí está mi versión de herramientas:

  • paquete web: "3.8.1"
  • electrón: "4.2.1"

Creo que electron-renderer solo para resolver este problema de los electrones. No necesito usar una sintaxis cableada como window.required , ¡e incluso perdió la escritura!

Para mí, trabajé configurando el objetivo: "renderizado de electrones" para webpack y nodeIntegration: verdadero en las opciones de BrowserWindow
Estoy usando webpack + electron + react de las últimas versiones de hoy

Estoy ejecutando create-react-app con TypeScript y Electron. Seguí estas muy buenas instrucciones para una configuración. Pero luego también encontré este error. La solución que me funciona es la suma de las cosas que se dicen en este hilo:

  1. Haga que el script de reacción use "electron-renderer" como target . Utilizo rescripts con rescript-env para esto.

package.json

  "rescripts": [
    "env"
  ],

.rescriptsrc.js

module.exports = [require.resolve ("./ webpack.config.js")];

webpack.config.js :

module.exports = config => {
  config.target = "electron-renderer";
  return config;
};
  1. Agregar nodeIntegration
new BrowserWindow({
  webPreferences: {
    nodeIntegration: true
  }
});
  1. Agregar src/typings.d.ts :
declare var window: Window;
interface Window {
  require: any;
}

Y finalmente has visto en tu aplicación

App.tsx

const { remote } = window.require("electron");
console.log(remote.getCurrentWindow());

@LukasBombach
Esto también debería funcionar:

declare var window: Window;
interface Window {
  require: NodeRequire
}

Entonces tendrás que escribir las consts requeridas.

¡Gracias!

Estos son los pasos que utilicé para Vue en caso de que sea útil para otra persona.

Asegúrese de que la integración de nodos esté habilitada para el proceso de renderizado agregándola a las preferencias web al crear una ventana del navegador:

new BrowserWindow({
    webPreferences: {
        nodeIntegration: true,
    },
})
````

Configure webpack to package your application for electron renderer by adding a target to your `vue.config.js` (or wherever you set your vue settings). 
```js
module.exports = {
    configureWebpack: {
        target: 'electron-renderer',
    },
}

Importa lo que necesitas dentro de tu aplicación. Estoy importando el módulo de shell en mi componente así:

import { shell } from 'electron'

Para cualquiera que siga teniendo el mismo problema. Esta es la mejor solución que he encontrado hasta ahora.

`` js
nueva ventana del navegador ({
webPreferences: {
nodeIntegration: verdadero
}
});

Espero que se note este comentario, porque mucha gente pregunta sobre la importación de fs o ipcRenderer en sus aplicaciones. Es una necesidad común para las aplicaciones electrónicas, pero descubrí que no muchas personas lo han hecho bien y están usando patrones obsoletos. tl; dr : existe una vulnerabilidad de seguridad si no importa su módulo de nodo (es decir, fs ) o módulo electrónico (es decir, ipcRenderer ) de la manera correcta. Si está utilizando su aplicación solo para usted, es _probablemente_ seguro, pero si alguna vez desea compartir o vender su aplicación, debe leer con anticipación.

Nuestro objetivo

Antes de entrar en la solución, es importante comprender _por qué_ estamos haciendo esto en primer lugar. Las aplicaciones de Electron nos permiten incluir módulos de nodo en nuestras aplicaciones, lo que les da un poder asombroso, pero preocupaciones de seguridad. Queremos permitir que nuestra aplicación use características de sistema operativo nativo (es decir, nodo), pero no queremos que se abuse de ellas .

Como lo mencionó @raddevus en un comentario, esto es necesario al cargar contenido remoto. Si su aplicación electron está completamente fuera de línea / local, entonces probablemente esté bien simplemente activando nodeIntegration:true . Sin embargo, todavía optaría por mantener nodeIntegration:false para actuar como una protección para los usuarios accidentales / malintencionados que usan su aplicación, y evitar que cualquier posible malware que pueda instalarse en su máquina interactúe con su aplicación electron y use el vector de ataque nodeIntegration:true (increíblemente raro, pero podría suceder).

La manera fácil

La configuración de nodeIntegration: true en su BrowserWindow le da a su proceso de renderizado acceso a los módulos del nodo. Hacer esto es vulnerable. Tiene acceso a require("fs") y require("electron") , pero eso significa que si alguien encontrara una vulnerabilidad XSS, podría ejecutar cualquier comando que haya expuesto en su proceso de renderizado.

Piense en eliminar todos los archivos de su computadora o en algo más que sea realmente malo.

La forma (alternativa) fácil

Además de establecer nodeIntegration en verdadero, es probable que su aplicación esté usando webpack para agrupar archivos de la aplicación. Webpack se equivoca con ciertos símbolos, por lo que configuraciones como target: 'electron-renderer' o externos del paquete web le permiten pasar estas variables ( ipcRenderer ) a su aplicación.

Aún así, esto no cambia nada excepto cómo está configurando su aplicación.

La manera fácil (otra alternativa)

Puede usar el módulo remoto que le da acceso a ipcRenderer . Básicamente es 'La manera fácil' en una forma diferente. Las recomendaciones de seguridad de Electron no recomiendan hacer esto, ya que este tipo de ataque sufre de un vector de contaminación prototipo.

Es decir. el uso de control remoto podría permitir que alguien modifique el prototipo de un objeto js y cause estragos en su máquina / aplicación.

La _casi_ forma correcta

@marksyzm tiene una solución mejor , aunque no perfecta, donde usamos IPC para enviar el ipcRenderer al proceso de renderizado. Este tipo de configuración también es vulnerable a prototipos de ataques de

La direccion correcta

La forma correcta de importar su fs / ipcRenderer en su proceso de renderizado es con IPC (comunicación entre procesos). Esta es la forma de Electron de permitirle hablar entre el proceso principal y el del renderizador. Desglosado, así es como debe verse su aplicación:

  1. Un BrowserWindow tiene una propiedad preload . Esta propiedad es un archivo js que se carga con acceso a require (lo que significa que puede requerir ipcRenderer)
  2. Su BrowserWindow también tendrá contextIsolation: true para evitar prototipos de ataques de contaminación, pero esto significa que debe usar contextBridge para pasar el ipcRenderer a su proceso de renderizado
  3. Usando el script de precarga y el contextBridge, permite que su proceso de renderizado acceda a ipcRenderer
  4. En su secuencia de comandos principal, crea oyentes para ipcRenderer (en el módulo ipcMain ). Dentro de estos oyentes puede usar el módulo fs

_ Aproximadamente_ así es como se ven todos estos pasos:

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>

Como mínimo, creo que necesitas electron v7 para estas funciones.

¿Cómo sé esto?

Me preocupan las aplicaciones electrónicas seguras y construí secure-electron-template para crear una plantilla de aplicación electrónica para incorporar la seguridad en lugar de pensar en la seguridad como una ocurrencia tardía.

Sobre la base del comentario anterior de preload.js , donde mi API es más cercana a la de ipcRenderer.

main.js

let newWindow = null;
function createWindow() {
    newWindow = new BrowserWindow({
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            enableRemoteModule: false,
            preload: path.join(__dirname, "preload.js")
        }
    });

    newWindow.webContents.on('did-finish-load', () => {
        newWindow.webContents.send('APP_MY_INIT', { data: 'hi' });
    });
}

ipcMain.on('APP_SOMETHING', (event, ...args) => {
    // ...
});

ipcMain.handle('APP_SOMETHING_ELSE', (event, ...args) => {
    // ...
    return myVar;
});

preload.js

const { contextBridge, ipcRenderer } = require('electron');

function callIpcRenderer(method, channel, ...args) {
    if (typeof channel !== 'string' || !channel.startsWith('APP_')) {
        throw 'Error: IPC channel name not allowed';
    }
    if (['invoke', 'send'].includes(method)) {
        return ipcRenderer[method](channel, ...args);
    }
    if ('on' === method) {
        const listener = args[0];
        if (!listener) throw 'Listener must be provided';

        // Wrap the given listener in a new function to avoid exposing
        // the `event` arg to our renderer.
        const wrappedListener = (_event, ...a) => listener(...a);
        ipcRenderer.on(channel, wrappedListener);

        // The returned function must not return anything (and NOT
        // return the value from `removeListener()`) to avoid exposing ipcRenderer.
        return () => { ipcRenderer.removeListener(channel, wrappedListener); };
    }
}

contextBridge.exposeInMainWorld(
    'myIpcRenderer', {
        invoke: (...args) => callIpcRenderer('invoke', ...args),
        send: (...args) => callIpcRenderer('send', ...args),
        on: (...args) => callIpcRenderer('on', ...args),
    },
);

client.js

const { myIpcRenderer } = window;

const removeMyListener = myIpcRenderer.on('APP_MY_INIT', data => {
    console.log(data);
    myIpcRenderer.send('APP_SOMETHING', 'foo');
})

async function test() {
    const result = await myIpcRenderer.invoke('APP_SOMETHING_ELSE', 'foo', 'bar');
    console.log(result);
}
test();

if (/* should remove listener === true */) {
    removeMyListener();
}

Y para aquellos que usan TypeScript, types.d.ts

declare global {
    interface Window {
        myIpcRenderer: MyIpcRenderer,
    }
}

export interface MyIpcRenderer {
    invoke(channel: string, ...args: any[]): Promise<any>;
    send(channel: string, ...args: any[]): void;

    /** <strong i="22">@return</strong> A function that removes this listener. */
    on(channel: string, listener: (...args: any[]) => void): () => void;
}

¿Alguien sabe por qué obtengo el error de módulo no encontrado cuando intento poner esto en preload.js?

const errorLogging = require('../renderer/utils/errorLogging');

Gracias

@silentlight esto no está relacionado con el electrón, ¿quizás tienes un repositorio de github propio donde la conversación puede continuar? (Parece que su ruta en require() no es correcta y es por eso que arroja un error, sin ver más código).

Aunque ya existe la solución window.require , voy a compartir la mía, solo por diversión:

function magic(module){
    require(module)
}

const { ipcRenderer } = magic('electron')

Sus empaquetadores no se identificarán cuando esté importando un módulo, ya que no está utilizando módulos ES o sintaxis CommonJS, por lo que no intentará empaquetarlo y, por lo tanto, no arrojará un error.

Me pregunto por qué nadie ha probado esto todavía 😆

@ marc2332 cierto, pero luego te expones directamente a posibles ataques de esta envoltura mágica. Puede que no se aplique a su escenario, pero definitivamente es una preocupación que debe considerar.

@reZach No veo razones por las que window.require sea más seguro para ser honesto. Por cierto, hay formas más sucias de hacerlo.

const { ipcRenderer } = eval("require('electron')")

@ marc2332 ninguno es seguro. Solo estoy señalando que si usa activos remotos, se está abriendo a ataques de inyección de esta manera. 😄

¡Gracias reZach! Creo que la gente comprenderá su enfoque antes

o después

Mark Elphinstone
www.oxfordsourceltd.com

Hola Zach, ¿la solución contextBridge admite prototipos?

Mi código original con contextIsolation: false simplemente adjuntó una función en window . Esta función devuelve Promise<MediaStream> sin embargo, los documentos de contextBridge dicen que los prototipos se descartan y cuando utilicé contextBridge recibo un objeto vacío.

¿Hay alguna manera de admitir prototipos pero también de garantizar contextIsolation: true ?

Hola Zach, ¿la solución contextBridge admite prototipos?

Mi código original con contextIsolation: false simplemente adjuntó una función en window . Esta función devuelve Promise<MediaStream> sin embargo, los documentos de contextBridge dicen que los prototipos se descartan y cuando utilicé contextBridge recibo un objeto vacío.

¿Hay alguna manera de admitir prototipos pero también de garantizar contextIsolation: true ?

No, no es así. Estaba tratando de encontrar un comentario que recuerdo de uno de los miembros del equipo de que se trata de un comportamiento intencionado, pero no pude. Lo mejor que puedo decir es que en Electron v8, ( pr 20214 ) se produjeron cambios en la serialización de objetos dentro de IPC (efectivamente cuando el aislamiento de contexto está

NOTA: Los objetos que no se pueden serializar con el algoritmo de clonación estructurada de V8, como funciones, objetos DOM, objetos especiales Node / Electron como process.env o WebContents, o cualquier objeto que contenga dichos elementos se serializarán con la base anterior :: Value- algoritmo basado. Sin embargo, este comportamiento está en desuso y generará una excepción a partir de Electron 9.

Probablemente esta no sea la noticia que querías escuchar, pero espero haberlo ayudado.

Hola Zach, ¿la solución contextBridge admite prototipos?
Mi código original con contextIsolation: false simplemente adjuntó una función en window . Esta función devuelve Promise<MediaStream> sin embargo, los documentos de contextBridge dicen que los prototipos se descartan y cuando utilicé contextBridge recibo un objeto vacío.
¿Hay alguna manera de admitir prototipos pero también de garantizar contextIsolation: true ?

No, no es así. Estaba tratando de encontrar un comentario que recuerdo de uno de los miembros del equipo de que se trata de un comportamiento intencionado, pero no pude. Lo mejor que puedo decir es que en Electron v8, ( pr 20214 ) se produjeron cambios en la serialización de objetos dentro de IPC (efectivamente cuando el aislamiento de contexto está

NOTA: Los objetos que no se pueden serializar con el algoritmo de clonación estructurada de V8, como funciones, objetos DOM, objetos especiales Node / Electron como process.env o WebContents, o cualquier objeto que contenga dichos elementos se serializarán con la base anterior :: Value- algoritmo basado. Sin embargo, este comportamiento está en desuso y generará una excepción a partir de Electron 9.

Probablemente esta no sea la noticia que querías escuchar, pero espero haberlo ayudado.

Eso es lamentable, pero gracias por su rápida respuesta.

Seguí los pasos descritos anteriormente (dados por @reZach y @aplum), y estoy pasando información de mi client.js al preload.js a main.js .

Cuando ejecuto todo localmente, la comunicación funciona, pero cuando ejecuto electron-builder , la comunicación se interrumpe. Por ejemplo, usar setBadge() funciona maravillosamente cuando se ejecuta localmente. Puedo tomar el recuento del archivo client.js y ver que se pasa al contextBridge y luego a main.js y configurar con éxito el app.dock.setBadge(count) . ¿Hay algo que me falta con la comunicación en Electron después de que se construyó con electron-builder ?.

"electron": "^8.2.3",
"electron-builder": "^22.4.0",

Main.js

const { ipcMain } = electron;

app.on('ready', () => {
    mainWindow = new BrowserWindow({
        height: height,
        width: width,
        minHeight: 575,
        minWidth: 900,
        center: true,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            enableRemoteModule: false,
            spellcheck: true,
            preload: path.join(__dirname, "preload.js")
        },
    });
}

ipcMain.on('SEND_BADGE_COUNT', (e, count) => {
    const badgeCount = count > 0 ? count : '';
    app.dock.setBadge(`${badgeCount}`)
})

Preload.js

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld(
    'setBadgeCountForElectron', {
        send: (channel, data) => {
            console.log(`Preload ${channel}, ${data}`)
            ipcRenderer.send(channel, data)
        }
    }
)

Client.js

const { setBadgeCountForElectron } = window;

function sendBadgeCount(count) {
  !!setBadgeCountForElectron && setBadgeCountForElectron.send('SEND_BADGE_COUNT', count)
}

sendBadgeCount(count)

package.json

  "name": "desktop_app",
  "version": "0.1.8-beta",
  "private": true,
  "description": "",
  "homepage": "./",
  "main": "public/electron.js",
  "build": {
    "copyright": "Copyright © 2020 My Company",
    "appId": "com.my-app.app",
    "productName": "My Company",
    "buildVersion": "0.0.1-beta",
    "mac": {
      "category": "public.app-category.utilities",
      "icon": "./public/images/mac-icon.png"
    },
    "win": {
      "icon": "./public/images/windows-icon.png"
    },
    "files": [
      "build/**/*",
      "node_modules/**/*"
    ],
    "directories": {
      "buildResources": "assets"
    }
  },

@SterlingChin , no soy un mantenedor del equipo de electrones, pero esta podría ser una pregunta más adecuada para el repositorio de construcción de electrones.

Me inclino más a pensar que es un problema con el código que con el generador de electrones cuando me tomé un momento para pensarlo.

Me inclino más a pensar que es un problema con el código que con el generador de electrones cuando me tomé un momento para pensarlo.

Estoy seguro de que me falta alguna pieza clave que haría que todo esto funcionara como se esperaba. Gracias por su respuesta. Abrí un problema en el repositorio electron-builder , pero no ha recibido ningún impulso.

Me inclino más a pensar que es un problema con el código que con el generador de electrones cuando me tomé un momento para pensarlo.

Estoy seguro de que me falta alguna pieza clave que haría que todo esto funcionara como se esperaba. Gracias por su respuesta. Abrí un problema en el repositorio electron-builder , pero no ha recibido ningún impulso.

¿Ha creado un repositorio MVP con su problema? Eso a veces ayuda y en el proceso te das cuenta de lo que está pasando.

@Amthieu y @CiriousJoker los amo a ambos, gracias.

  1. añadir hilo -D personalizar-cra react-app-rewired
  2. modificar package.json para usar la aplicación de inicio react-app-rewired: "start": "BROWSER = none react-app-rewired start",
  3. cree el archivo 'config-overrides' en el directorio raíz de la aplicación de reacción:
    `const {override} = require ('personalizar-cra');

function addRendererTarget (config) {
config.target = 'renderizador de electrones';

return config;
}

module.exports = override (addRendererTarget); `

  1. podría importar {ipcRenderer} desde 'electron' ahora :)

Estoy usando vuejs y solo agrego el código en vue.config.js

module.exports = {
"transpileDependencies": [
"vuetificar"
],
pluginOptions: {
electronBuilder: {
nodeIntegration: verdadero
}
}
}

@genilsonmm ¡Mierda que funcionó! Me he estado volviendo loco durante las últimas 3 horas. ¡¡Gracias!!
La parte específica de eso que funcionó para mí fue la
javascript
pluginOptions: {
electronBuilder: {
nodeIntegration: verdadero
}
},

"transpileDependencies": [
"vuetificar"
],

eso no me funciona ... pero window.require ('electron') está funcionando bien

Para todas las personas que tienen el problema "window.require no es una función"

Tienes que crear un script de precarga en electron.

  1. Cree un archivo llamado preload.js en el directorio donde tiene el script principal de electron, coloque este código en él:

    window.require = require;

  2. Vaya a su secuencia de comandos principal de electron y escriba esto en el código donde crea la ventana:

    win = new BrowserWindow ({
    ancho: 1280,
    altura: 720,
    webPreferences: {
    nodeIntegration: falso,
    precarga: __dirname + '/preload.js'
    },

    })
    Con esto, precargará el script antes de todo, esto me solucionó el problema. Espero también para ti :)

@reZach, tu solución funcionó para mí, pero noté un error con el que otras personas podrían tropezar (porque yo lo hice, ¡vaya!):

        receive: (channel, func) => {
            let validChannels = ["fromMain"];
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender` 
                ipcRenderer.on(channel, (event, ...args) => fn(...args));
            }
        }

define su función de devolución de llamada como "func", pero luego llama "fn", si cambia esto, funciona exactamente como lo describe.
Muchas gracias por la publicación detallada: +1:

@genilsonmm Si pongo vue.config.js:

pluginOptions: {
electronBuilder: {
nodeIntegration: verdadero,

Recibo el error "require no está definido":

image

Si comento la línea "nodeIntegration: true", el mensaje de error desaparece y la aplicación funciona.

Qué significa eso?

@marcoippolito Creo que significa que el código del paquete web está tratando de usar require que es el método de resolución del módulo de node js. Dado que esto no está disponible si deshabilita la integración de nodos, el código no se puede ejecutar. Lo que debe hacer es modificar la configuración de su paquete web para apuntar a los navegadores ( var es el objetivo si mal no recuerdo) y asegurarse de que ninguno de su código esté usando apis de nodo y el error debería desaparecer.

Para aquellos que usan TypeScript, hay un buen ejemplo en los ejemplos oficiales de Next.js:
https://github.com/vercel/next.js/search?q=ipcRenderer&unscoped_q=ipcRenderer

preload.ts

/* eslint-disable @typescript-eslint/no-namespace */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { ipcRenderer, IpcRenderer } from 'electron'

declare global {
  namespace NodeJS {
    interface Global {
      ipcRenderer: IpcRenderer
    }
  }
}

// Since we disabled nodeIntegration we can reintroduce
// needed node functionality here
process.once('loaded', () => {
  global.ipcRenderer = ipcRenderer
})

index.tsx

import { useState, useEffect } from 'react'

const Home = () => {
  const [input, setInput] = useState('')
  const [message, setMessage] = useState(null)

  useEffect(() => {
    const handleMessage = (event, message) => setMessage(message)
    global.ipcRenderer.on('message', handleMessage)

    return () => {
      global.ipcRenderer.removeListener('message', handleMessage)
    }
  }, [])

  const handleSubmit = (event) => {
    event.preventDefault()
    global.ipcRenderer.send('message', input)
    setMessage(null)
  }

  return (
    <div>
      <h1>Hello Electron!</h1>
    </div>
  )
}

export default Home

@genilsonmm ¡Mierda que funcionó! Me he estado volviendo loco durante las últimas 3 horas. ¡¡Gracias!!
La parte específica de eso que funcionó para mí fue la

   pluginOptions: {
        electronBuilder: {
            nodeIntegration: true
        }
    },

正 解 , 标记

También tengo este problema con NodeIntegration habilitado. Tanto window.require como require no funcionan.

+ Esto solo sucede con reaccionar, no con electrones simples

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

dangan-ronpa picture dangan-ronpa  ·  3Comentarios

chonsser picture chonsser  ·  3Comentarios

ThorstenHans picture ThorstenHans  ·  3Comentarios

christiangenco picture christiangenco  ·  3Comentarios

tenry92 picture tenry92  ·  3Comentarios