Qué es el script de preload en las aplicaciones de Electron y cómo lo podemos usar para enviar datos desde NodeJS hacia la página web que se ejecuta en la ventana de la aplicación gracias al objeto contextBridge.
En este artículo vamos a seguir dando los primeros pasos en Electron, con una demostración sobre cómo podemos enviar datos simples desde el proceso de NodeJS que se ejecuta en el ordenador del usuario a la página web que se ejecuta en la ventana de la aplicación.
Este es el mecanismo con el que podremos conseguir que los usuarios de las aplicaciones puedan realizar acciones fuera del contexto de la página web que se ejecuta en la ventaja de Electron, abriendo las puertas a la funcionalidad disponible en Node. Sin embargo, de momento las prácticas que vamos a realizar serán muy elementales, dejando para más adelante asuntos más complejos.
Tienes disponible en el Manual de Electron toda una serie de artículos previos, que deberías haber leído para poder entender la materia que vamos a abordar a continuación.
Los pasos para enviar datos generados en NodeJS al frontend de Electron Son los siguientes.
Qué es el script de Preload de Electron
El script "preload" de las aplicaciones de Electron se encarga de servir de puente entre la página web que se ejecuta en la ventana de la aplicación y el proceso de NodeJS que se ejecuta en el ordenador del usuario.
Por medio de este script podemos generar datos y funcionalidades que luego se podrán invocar desde las interfaces de usuario web que tenemos en el index.html
.
Como conocimiento general también debes saber que el script de Preload ofrece de manera predeterminada una funcionalidad limitada dentro de NodeJS, ya que se ejecuta en un entorno denominado "sandbox". El sandbox es una medida de seguridad que se incluye en Chromium y que está heredada en Electron desde la versión 20. De todos modos, vía configuración podemos deshabilitar el sandbox para un proceso, con lo que podríamos llegar a evitar esas limitaciones. Si no hacemos nada debemos saber que el Preload ofrece solamente un subset de todo lo que podríamos hacer en Node. La recomendación es mantenerse dentro del sandbox para aumentar la seguridad de las aplicaciones.
Objeto contextBridge
El objeto contextBridge
que nos ofrece Electrón es el responsable de hacer de puente, enviando información a la página web que se ejecuta en la ventana, así como recibiendo órdenes para ejecutar funcionalidades incorporadas.
Para acceder a este objeto hacemos el siguiente require:
const { contextBridge } = require('electron');
Luego podemos crear datos para ser accedidos desde el frontend, de esta manera:
contextBridge.exposeInMainWorld('appName', 'Hola Mundo App');
Por si no queda claro, estamos viendo código que se ejecutará en el preload process de tu aplicación. Generalmente el archivo de preload se llamará
preload.js
(opreload.ts
si estás trabajando con TypeScript) y estará al lado delmain.js
. Recuerda que al crear la ventana del navegador, en el código delmain.js
teníamos una propiedadwebPreferences
donde se debió indicar el archivo de preload, necesario para quepreload.js
se cargue adecuadamente para la página que arranque tu app. Esa configuración la vimos en el artículo anterior dedicado a la Arquitectura básica de las aplicaciones en Electron.
En este caso estamos usando el método exposeInMainWorld
que nos permite crear una especie de variable llamada "appName
", a la que le estamos aplicando ya un valor de tipo cadena. Podremos acceder a esta variable desde la página web que se ejecuta en la aplicación.
Por supuesto, además de datos sencillos podremos enviar otros más complejos como objetos.
contextBridge.exposeInMainWorld('nodeData', {
foo: 'bla bla',
node: () => process.versions.node,
sum: (x, y) => x + y,
});
En este caso estamos creando una variable llamada "nodeData
" que contiene un objeto. En el objeto podemos crear propiedades simples como "foo
" o incluso propiedades que contienen métodos como "node
" que nos devuelve la versión de NodeJS que tenemos disponible. También tenemos una función "sum
" que recibe un par de parámetros y devuelve su suma.
Para ver un primer ejemplo de script de preload tenemos este código completo:
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('nodeData', {
foo: 'bla bla',
node: () => process.versions.node,
sum: (x, y) => x + y,
});
contextBridge.exposeInMainWorld('appName', 'Hola Mundo App');
Cómo asociar el script de preload a la ventana
Para poder ejecutar este script de Preload y que esté disponible en la ventana del navegador tenemos que configurarlo en el archivo main.js
, dentro de la función que se encargaba de especificar las propiedades de la ventana.
Para ello usamos una propiedad llamada "webPreferences
" que a su vez contiene un objeto que tiene la propiedad "preload
", en la que indicamos la ruta para acceder al script de preload.
El código nos quedaría como se puede ver aquí:
const { app, BrowserWindow } = require('electron')
const path = require('path')
const createWindow = () => {
const win = new BrowserWindow({
width: 400,
height: 300,
webPreferences: {
preload: path.join(__dirname, 'modules', 'preload.js'),
},
})
win.loadFile('index.html')
}
El módulo path, así como el método path.join() o la explicación de __dirname los puedes consultar en el artículo de path en el Manual de NodeJS.
Cómo acceder a los datos enviados por el script de Preload
Ahora vamos a ver un ejemplo de página web que contiene un script que hemos implementado para poder acceder a los datos que nos está entregando el script de preload.js
.
Como verás, los datos los podemos acceder directamente como si fueran variables globales. Los nombres de las variables son los mismos que se indicaron al crear los datos con el método exposeInMainWorld
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Usar datos del preload script con Electron</title>
</head>
<body>
<h1></h1>
<p id="foo"></p>
<p id="version"></p>
<p id="suma"></p>
<script>
const h1 = document.querySelector('h1');
h1.innerText = `Bienvenidos a ${appName}`;
const foo = document.getElementById('foo');
foo.innerText = `Usamos node versión ${nodeData.foo}`;
const version = document.getElementById('version');
version.innerText = `Usamos node versión ${nodeData.node()}`;
const suma = document.getElementById('suma');
suma.innerText = `La suma de 3 y 9 da ${nodeData.sum(3, 9)}`;
</script>
</body>
</html>
Simplemente hemos hecho unos accesos al DOM del documento HTML y hemos cargado los distintos datos por separado en varios párrafos. Si ya tienes conocimientos de desarrollo frontend verás que no hay mucho misterio!!
Espero que te haya gustado este artículo y que ya comiences a ver algunas de las posibilidades que nos ofrece Electron. En el siguiente artículo seguiremos analizando este puente entre el frontend y nuestro código NodeJS, para conseguir ejecutar otras funciones más específicas de Node.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...