En el desarrollo de aplicaciones de escritorio con Electron, la arquitectura se divide principalmente en dos contextos aislados: el proceso principal (Main Process) y el proceso de renderizado (Renderer Process). Para que estos dos entornos puedan intercambiar datos de manera segura y eficiente, el framework proporciona el módulo de Comunicación entre Procesos (IPC, por sus siglas en inglés).
Configuración del Proceso Principal
El proceso principle actúa como el núcleo de la aplicación, gestionando el ciclo de vida, las ventanas nativas y las operaciones del sistema. Utilizaremos el módulo ipcMain para escuchar los eventos enviados desde la interfaz de usuario y el método webContents.send para emitir respuestas o notificaciones.
A continuación, se presenta una implementación refactorizada. Se han eliminado dependencias obsoletas (como el módulo remote), actualizado los ciclos de vida con promesas y renombrado los canales de comunicación para seguir un patrón de nomenclatura claro.
const { app, BrowserWindow, ipcMain, globalShortcut } = require('electron');
let applicationWindow = null;
app.whenReady().then(() => {
applicationWindow = new BrowserWindow({
width: 1024,
height: 768,
webPreferences: {
// Nota: Configuración habilitada para fines demostrativos.
// En entornos de producción, utilice contextIsolation: true y un script preload.
nodeIntegration: true,
contextIsolation: false
}
});
applicationWindow.loadFile('interface.html');
// Emisión de un mensaje asíncrono hacia el renderizador una vez que el DOM esté listo
applicationWindow.webContents.on('did-finish-load', () => {
applicationWindow.webContents.send('backend:status-update', 'El núcleo de la aplicación está activo y listo.');
});
applicationWindow.on('closed', () => {
applicationWindow = null; // Liberación de recursos
});
});
app.on('will-quit', () => {
globalShortcut.unregisterAll(); // Limpieza de atajos de teclado globales
});
// Suscripción a mensajes asíncronos provenientes del renderizador
ipcMain.on('frontend:submit-data', (event, payload) => {
console.log(`[Proceso Principal] Datos interceptados: ${payload}`);
// Respuesta dirigida al canal específico del emisor
event.reply('backend:acknowledge', `Confirmación: El backend procesó "${payload}" correctamente.`);
});
// Manejo de solicitudes síncronas (bloqueantes)
ipcMain.on('frontend:sync-request', (event, payload) => {
console.log(`[Proceso Principal] Solicitud síncrona recibida: ${payload}`);
// Retorno inmediato de valor al hilo del renderizador
event.returnValue = `Respuesta síncrona generada para: ${payload}`;
});
Implementación en el Proceso de Renderizado
En la capa de presentación, el módulo ipcRenderer permite a la interfaz enviar solicitudes al backend de Node.js y suscribirse a las actualizaciones del estado. En este ejemplo, se moderniza el código HTML/JS utilizando escuchas de eventos nativas del DOM (addEventListener) en lugar de atributos en línea, mejorando la separación de responsabilidades.
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Panel de Comunicación IPC</title>
</head>
<body>
<h2>Consola de Mensajería</h2>
<input type="text" id="dataInput" placeholder="Ingrese un mensaje...">
<button id="btnAsync">Emitir Evento Asíncrono</button>
<button id="btnSync">Emitir Evento Síncrono</button>
<script>
const { ipcRenderer } = require('electron');
// Escucha de notificaciones de estado del backend
ipcRenderer.on('backend:status-update', (event, statusMessage) => {
console.log(`[Renderizador] Notificación del sistema: ${statusMessage}`);
});
// Escucha de confirmaciones asíncronas
ipcRenderer.on('backend:acknowledge', (event, responsePayload) => {
alert(responsePayload);
});
// Lógica para el flujo de comunicación asíncrono
document.getElementById('btnAsync').addEventListener('click', () => {
const inputValue = document.getElementById('dataInput').value;
if (inputValue.trim() !== '') {
ipcRenderer.send('frontend:submit-data', inputValue);
}
});
// Lógica para el flujo de comunicación síncrono
document.getElementById('btnSync').addEventListener('click', () => {
const inputValue = document.getElementById('dataInput').value;
if (inputValue.trim() !== '') {
const syncResult = ipcRenderer.sendSync('frontend:sync-request', inputValue);
console.log('Resultado síncrono inmediato:', syncResult);
alert(syncResult);
}
});
</script>
</body>
</html>