Instrucciones para convertir el archivo HTML a aplicación de escritorio con Electron

📦 PASO 1: Preparar el entorno

1.1 Instalar Node.js

  1. Ve a nodejs.org
  2. Descarga e instala la versión LTS (Long Term Support)

1.2 Verificar instalación

Abre la terminal o PowerShell y ejecuta:

node --version
npm --version

📁 PASO 2: Estructura del proyecto

En C:\Users\migue\Desktop\Demo Mycomunidad, crea esta estructura:

demo Mycomunidad/
├── index.html           # Tu archivo HTML (ya lo tienes)
├── main.js             # Archivo principal de Electron
├── package.json        # Configuración del proyecto
├── preload.js         # Script de pre-carga (opcional)
└── assets/            # Carpeta para recursos (opcional)

📝 PASO 3: Crear los archivos necesarios

3.1 Crear package.json

Crea un archivo package.json en la misma carpeta con este contenido:

{
  "name": "mycomunidad-demo",
  "version": "1.0.0",
  "description": "Sistema de Administración de Condominios DEMO",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "pack": "electron-builder --dir",
    "dist": "electron-builder",
    "dist-win": "electron-builder --win",
    "dist-mac": "electron-builder --mac",
    "dist-linux": "electron-builder --linux"
  },
  "keywords": [
    "condominios",
    "administración",
    "demo",
    "sistema"
  ],
  "author": "Miguel Urbaez",
  "license": "MIT",
  "devDependencies": {
    "electron": "^25.0.0",
    "electron-builder": "^24.6.4"
  },
  "build": {
    "appId": "com.totumsoft.mycomunidad.demo",
    "productName": "MyComunidad DEMO",
    "directories": {
      "output": "dist"
    },
    "files": [
      "**/*",
      "!node_modules/**/*"
    ],
    "win": {
      "target": "nsis",
      "icon": "assets/icon.ico"
    },
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true,
      "createDesktopShortcut": true,
      "createStartMenuShortcut": true
    },
    "mac": {
      "target": "dmg",
      "icon": "assets/icon.icns"
    },
    "linux": {
      "target": "AppImage",
      "icon": "assets/icon.png"
    }
  }
}

3.2 Crear main.js

Crea un archivo main.js con este contenido:

const { app, BrowserWindow, Menu, ipcMain, dialog } = require('electron');
const path = require('path');
const fs = require('fs');

// Variable para mantener referencia a la ventana principal
let mainWindow;

// Crear menú personalizado (opcional, sin íconos como solicitaste)
function createMenu() {
  const template = [
    {
      label: 'Archivo',
      submenu: [
        {
          label: 'Salir',
          accelerator: 'CmdOrCtrl+Q',
          click: () => app.quit()
        }
      ]
    },
    {
      label: 'Editar',
      submenu: [
        { label: 'Deshacer', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
        { label: 'Rehacer', accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' },
        { type: 'separator' },
        { label: 'Cortar', accelerator: 'CmdOrCtrl+X', role: 'cut' },
        { label: 'Copiar', accelerator: 'CmdOrCtrl+C', role: 'copy' },
        { label: 'Pegar', accelerator: 'CmdOrCtrl+V', role: 'paste' },
        { label: 'Seleccionar Todo', accelerator: 'CmdOrCtrl+A', role: 'selectAll' }
      ]
    },
    {
      label: 'Ver',
      submenu: [
        { label: 'Recargar', accelerator: 'CmdOrCtrl+R', click: () => mainWindow.reload() },
        { label: 'Herramientas de Desarrollo', accelerator: 'F12', click: () => mainWindow.webContents.toggleDevTools() },
        { type: 'separator' },
        { label: 'Pantalla Completa', accelerator: 'F11', click: () => mainWindow.setFullScreen(!mainWindow.isFullScreen()) }
      ]
    },
    {
      label: 'Ayuda',
      submenu: [
        {
          label: 'Acerca de',
          click: () => {
            dialog.showMessageBox(mainWindow, {
              type: 'info',
              title: 'Acerca de MyComunidad DEMO',
              message: 'MyComunidad DEMO - Sistema de Administración de Condominios',
              detail: `Versión: 1.0.0\nDesarrollado por: Miguel Urbaez\n© 2025 Totumsoft\n\nEsta es una versión de demostración para evaluación del sistema.`
            });
          }
        }
      ]
    }
  ];

  const menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);
}

// Crear la ventana principal
function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1400,
    height: 900,
    minWidth: 1024,
    minHeight: 768,
    icon: path.join(__dirname, 'assets', 'icon.png'),
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      enableRemoteModule: false,
      preload: path.join(__dirname, 'preload.js')
    },
    show: false,
    backgroundColor: '#f8f9fa'
  });

  // Cargar el archivo HTML
  mainWindow.loadFile('index.html');

  // Mostrar la ventana cuando esté lista
  mainWindow.once('ready-to-show', () => {
    mainWindow.show();
    mainWindow.maximize(); // Opcional: iniciar maximizado
  });

  // Evento cuando se cierra la ventana
  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  // Crear menú
  createMenu();
}

// Eventos de la aplicación
app.whenReady().then(createWindow);

// Salir cuando todas las ventanas estén cerradas
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

// IPC Handlers para funcionalidades específicas
ipcMain.handle('save-backup', async (event, data) => {
  try {
    const { filePath } = await dialog.showSaveDialog(mainWindow, {
      title: 'Guardar Respaldo',
      defaultPath: `respaldo-micomunidad-${new Date().toISOString().split('T')[0]}.json`,
      filters: [
        { name: 'Archivos JSON', extensions: ['json'] },
        { name: 'Todos los archivos', extensions: ['*'] }
      ]
    });

    if (filePath) {
      fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
      return { success: true, path: filePath };
    }
    return { success: false };
  } catch (error) {
    return { success: false, error: error.message };
  }
});

ipcMain.handle('load-backup', async () => {
  try {
    const { filePaths } = await dialog.showOpenDialog(mainWindow, {
      title: 'Cargar Respaldo',
      filters: [
        { name: 'Archivos JSON', extensions: ['json'] },
        { name: 'Todos los archivos', extensions: ['*'] }
      ],
      properties: ['openFile']
    });

    if (filePaths.length > 0) {
      const data = fs.readFileSync(filePaths[0], 'utf8');
      return { success: true, data: JSON.parse(data), path: filePaths[0] };
    }
    return { success: false };
  } catch (error) {
    return { success: false, error: error.message };
  }
});

ipcMain.handle('print-to-pdf', async (event, htmlContent) => {
  try {
    const { filePath } = await dialog.showSaveDialog(mainWindow, {
      title: 'Guardar PDF',
      defaultPath: `factura-${Date.now()}.pdf`,
      filters: [
        { name: 'Archivos PDF', extensions: ['pdf'] }
      ]
    });

    if (filePath) {
      // Aquí podrías implementar la generación de PDF
      // Por ahora solo creamos un archivo de ejemplo
      fs.writeFileSync(filePath, 'Contenido PDF aquí', 'utf8');
      return { success: true, path: filePath };
    }
    return { success: false };
  } catch (error) {
    return { success: false, error: error.message };
  }
});

3.3 Crear preload.js (opcional)

Crea un archivo preload.js para comunicación segura entre procesos:

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

// Exponer APIs seguras al renderer process
contextBridge.exposeInMainWorld('electronAPI', {
  // Para respaldo de datos
  saveBackup: (data) => ipcRenderer.invoke('save-backup', data),
  loadBackup: () => ipcRenderer.invoke('load-backup'),

  // Para impresión/PDF
  printToPDF: (htmlContent) => ipcRenderer.invoke('print-to-pdf', htmlContent),

  // Información del sistema
  getAppInfo: () => ({
    version: '1.0.0',
    name: 'MyComunidad DEMO',
    author: 'Miguel Urbaez'
  }),

  // Mostrar diálogo nativo
  showMessage: (title, message) => {
    ipcRenderer.send('show-message', { title, message });
  }
});

// Exponer version de Node y Electron para depuración
contextBridge.exposeInMainWorld('versions', {
  node: () => process.versions.node,
  chrome: () => process.versions.chrome,
  electron: () => process.versions.electron
});

🔧 PASO 4: Modificar tu archivo HTML

En tu archivo index.html, añade estas líneas al final del <body>, justo antes de </body>:

<!-- Script para integración con Electron -->
<script>
  // Detectar si estamos en Electron
  const isElectron = typeof window.electronAPI !== 'undefined';

  if (isElectron) {
    console.log('Ejecutando en Electron');

    // Opcional: Personalizar comportamiento para Electron
    document.addEventListener('DOMContentLoaded', function() {
      // Deshabilitar clic derecho en producción si quieres
      // document.addEventListener('contextmenu', e => e.preventDefault());

      // Cambiar título de la página
      document.title = 'MyComunidad DEMO - Aplicación de Escritorio';

      // Añadir indicador de versión
      const versionInfo = window.electronAPI.getAppInfo();
      const footer = document.querySelector('.developer-footer');
      if (footer) {
        footer.innerHTML += `<br><small>Aplicación de escritorio v${versionInfo.version}</small>`;
      }
    });
  } else {
    console.log('Ejecutando en navegador web');
  }
</script>

📦 PASO 5: Instalar dependencias

  1. Abre PowerShell o CMD en la carpeta C:\Users\migue\Desktop\Demo Mycomunidad
  2. Ejecuta:
npm install

Esto instalará Electron y electron-builder.

🚀 PASO 6: Probar la aplicación

Para probar en modo desarrollo:

npm start

📦 PASO 7: Construir el ejecutable

Para Windows:

npm run dist-win

Para crear instalador:

npm run dist

Los ejecutables se crearán en la carpeta dist/.

⚙️ PASO 8: Configuración adicional (opcional)

8.1 Configurar acceso a archivos locales

En main.js, puedes añadir estas configuraciones si necesitas acceso a archivos locales:

// Añade después de webPreferences en createWindow():
webPreferences: {
  nodeIntegration: false,
  contextIsolation: true,
  enableRemoteModule: false,
  preload: path.join(__dirname, 'preload.js'),
  webSecurity: false, // Solo para desarrollo
  allowRunningInsecureContent: false
}

8.2 Configurar protocolo personalizado

Para crear URLs tipo mycomunidad://:

// Añade después de app.whenReady()
if (process.defaultApp) {
  if (process.argv.length >= 2) {
    app.setAsDefaultProtocolClient('mycomunidad', process.execPath, [path.resolve(process.argv[1])]);
  }
} else {
  app.setAsDefaultProtocolClient('mycomunidad');
}

🛠️ PASO 9: Solucionar problemas comunes

Si obtienes errores de dependencias:

npm cache clean --force
rmdir /s node_modules
npm install

Si la aplicación no se cierra correctamente:

Añade en main.js:

app.on('before-quit', () => {
  // Guardar datos o limpiar recursos aquí
});

Si necesitas acceso a APIs nativas:

Crea una API segura en preload.js y exponla al renderer.

📝 PASO 10: Personalización final

Para cambiar el nombre de la aplicación:

Edita en package.json:

"productName": "Mi Nombre Personalizado"

Para deshabilitar las herramientas de desarrollo en producción:

En main.js:

// Comenta o elimina esta línea del menú:
// { label: 'Herramientas de Desarrollo', accelerator: 'F12', click: () => mainWindow.webContents.toggleDevTools() }

🎯 Resumen de comandos importantes

# Instalar dependencias
npm install

# Ejecutar en modo desarrollo
npm start

# Construir para Windows
npm run dist-win

# Construir para todos los sistemas
npm run dist

# Limpiar caché
npm cache clean --force

📁 Estructura final esperada:

C:\Users\migue\Desktop\Demo Mycomunidad\
│   index.html          (tu archivo original)
│   main.js             (nuevo)
│   package.json        (nuevo)
│   preload.js          (nuevo, opcional)
│   .gitignore          (recomendado)
├───node_modules        (generado por npm install)
└───dist               (generado por npm run dist)
        MyComunidad DEMO Setup.exe
        MyComunidad DEMO.exe

¡Listo! Ahora tienes tu aplicación HTML convertida en un software de escritorio con Electron. Puedes distribuir el archivo .exe desde la carpeta dist.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *