Iniciar un proyecto Electron

Para a comenzar un proyecto Electron para generar una aplicación de escritorio, tenemos que generar en nuestro disco duro una carpeta en la que trabajaremos el proyecto, con el nombre que queramos que tenga el mismo.

Vamos a trabajar con el terminal o la consola, situándonos en la carpeta que contendrá al proyecto e iniciaremos el proyecto de Node, nos hara una serie de preguntas para generar el archivo package.json que configura la aplicación, aunque después podemos editar el archivo y hacer los cambios que queramos conviene rellenar ya los que nos pide que son:

Una vez rellenado te pide que aceptes con yes o simplemente pulsando en enter.

npm init

Hemos dado el primer paso, si miramos en la carpeta veremos que nos ha creado un archivo package.json. Lo dejamos sin abrirlo en ningún editor y seguimos con el proceso de iniciar la aplicación.

Instalamos las librerías de Electron y las de electron-builder que usaremos para empaquetar y general los ejecutables e instaladores de la aplicación.

npm install electron --save-dev
npm install electron-builder --save-dev

Al final de la linea colocamos dev porque son librerías que usaremos solo en el proceso de desarrollo, esto lo explicare más cuando revisemos y personalicemos el archivo package.json.

Si estamos usando Git lo iniciamos en la carpeta, esto nos genera una carpeta oculta git que utiliza GIt para trabajar con el proyecto:

git init

También si usamos Git crearemos un archivo al lado de package.json llamado .gitignore en el que le indicamos a Git que carpetas y archivos no tiene que sincronizar con el proyecto. Le ponemos por defecto el siguiente contenido:

node_modules/
dist/

Son dos carpetas que tendrán mucho contenido y no interesa guardar en el proyecto, node_modules es donde Node guarda los paquetes y librerías que usa y dist es la carpeta que se generará al empaquetar la aplicación.

Seguidamente si ya sabemos que librerías npm va a usar nuestra aplicación las instalamos sin añadir detrás dev, ya que son librerías de uso en el proceso de uso de la aplicación. La forma de instalar una librería es:

npm install nombredelalibreria

La estructura del proyecto

Una vez hemos inicializado el proyecto e instalado las librerías tenemos en la carpeta un archivo package.json otro .gitignore y una carpeta node_modules, esa es la estructura básica, para que la aplicación funcione necesitamos dos archivos más: index.js, styles.css e index.html.

Estos archivos pueden estar junto a los anteriores pero yo prefiero colocarlos dentro de una carpeta src que es la que mantengo en Git y que contiene todo el código, imágenes y datos que voy generando y que luego usará la aplicación. Así que nos vamos a nuestro editor de código favorito y nos colocamos dentro de la carpeta del proyecto para crear una carpeta src.

Dentro de ella creamos un archivo index.html, se trata de un archivo estándar que debe de incluir la hoja de estilos y el html de inicio de la aplicación. Nuestra aplicación es una aplicación web y por lo tanto construimos el html como lo haríamos en una web que solo puede usar html, css y javascript sin lenguajes de servidor como php.

Otro elemento básico son los iconos que usará la aplicación para crear los archivos de instalación e identificarse en los listados de aplicaciones instaladas y en la barra de aplicaciones en uso, son un archivo de el icono con una resolución de 128 x 128 pixeles en los formatos: ico, png y icns, también en una subcarpeta el icono en formato png y resoluciones desde 1024 x 1024 hasta 16 x 16. Comienzo creando un icono en png a 1024×1024 de el genero los tamaños en png y para convertir la imagen png en ico y icns uso la herramienta online CloudConverter. Todos estos archivos los coloco en una subcarpeta llamada icons dentro de la carpeta src.

También tenemos el archivo index.js es el javascript que iniciará la aplicación en el definimos la configuración de la misma.

Las aplicaciones de Electron funcionan en dos procesos separados el que se comunica con el sistema operativo y puede realizar acciones sobre los espacios de almacenamiento y el que presenta información en pantalla y recoge la interacción del usuario. El archivo index.js es el único encargado de los procesos de comunicación con el sistema operativo y el que lanza al otro proceso que parte del index.html para generar y operar en el área de interacción con el usuario.

El archivo index.js

El archivo index.js tiene una gran importancia en el funcionamiento de la aplicación y acudiremos a hablar de él en varias partes de estos artículos, ahora vamos a explicar las partes principales que contiene.

En el archivo index.js vamos a cargar las utilidades de Electron y Node que necesitemos para generar la aplicación y realizar acciones. Esto se realiza al inicio del código para asegurarnos que estén cargados cuando vayamos a usarlos, por defecto para poder generar la pantalla de la aplicación cargamos los objetos app, BrowserWindow, Menu, url y path que usaremos para definir y generar esa pantalla:

const { app, BrowserWindow, Menu } = require('electron');
const url = require("url");
const path = require("path");

Usamos la orden require para cargar la librería que necesitamos, que deberíamos haber instalado previamente, estas que cargamos aquí las hemos instalado al instalar Electron.

Seguidamente colocaríamos las variables que vayamos a usar en la parte back o comunicación con el sistema, también podemos usar el objeto global para pasar el valor de estas variables a el front o el área de interacción, por ejemplo para identificar cual es la url base de la aplicación escribiríamos el siguiente código:

const apppath = app.getAppPath();
global.apppath = apppath;
const basepath = apppath + "/src/";
global.basepath = basepath;

Lo siguiente es configurar y como se hará el arranque de la aplicación, primero decidimos si queremos dejar visible el menú de el mini Chromium que en el proceso de desarrollo es útil pero en el de uso de la aplicación no, para quitarlo colocamos una línea de código que usa el objeto Menu, si queremos que se vea la comentamos situando delante dos barras inclinadas:

Menu.setApplicationMenu(false);

Seguidamente creamos un objeto y la función que genera ese BrowserWindow:

let mainWindow;
const createWindow = () => {    
mainWindow = new BrowserWindow({

Escondemos la aplicación hasta que no esta montada la pantalla

show: false,

El ancho y alto por defecto de la pantalla

width: 1000,
height: 800,

Frame muestra o esconde los botones minimizar y cerrar pantalla:

frame: true,

Si queremos que el fondo de la aplicación sea transparente:

transparent: false,

El color de fondo de la aplicación:

backgroundColor: '#ffffff',

El icono que muestra en la barra superior:

icon: basepath + '/icons/png/32x32.png',

Para que en el front podamos usar la orden required:

webPreferences: { nodeIntegration: true } });

En esta orden definimos cual es el archivo html que tiene que cargar:

mainWindow.loadURL(       
url.format({
pathname: path.join(__dirname, '/index.html'),       protocol: "file:",
slashes: true
}));

Como le hemos dicho previamente que no muestre la aplicación hasta que no este cargada aquí creamos la función que la muestra:

mainWindow.on('ready-to-show', function() {        
mainWindow.show();        
mainWindow.focus();   
});

Que hace cuando se cierra la aplicación:

mainWindow.on('closed', () => { mainWindow = null; });

Si queremos que la aplicación se carge a pantalla completa por defecto:

mainWindow.maximize();

Si queremos que abra la consola de inspección de Chromium:

mainWindow.webContents.openDevTools();
}; 

El siguiente bloque que usa el objeto app es el que inicia y termina la aplicación mediante los eventos ready, activate y window:

app.on('ready', createWindow);
app.on('window-all-closed', () => {    
if (process.platform !== 'darwin') { app.quit(); }
});
app.on('activate', () => {   
if (mainWindow === null) { createWindow(); }
});

A partir de aquí escribiremos el código que vayamos necesitando para el funcionamiento de la aplicación en el back (carga y escritura de archivos, etc..).

El archivo packaje.json

Ahora vamos a personalizar el archivo packaje.json, en el que definimos partes de la aplicación y la configuración de el empaquetado.

En el primer bloque le indicamos: el nombre de la aplicación, la versión, la descripción, las palabras clave y el archivo javascript inicial:

"name": "prueba",
"version": "1.0.0",
"description": "Pruebas de desarrollo de una aplicación con Electron",
"keywords": [    "aplicacion",    "web",    "electron"  ], 
"main": "src/index.js",

El siguiente bloque es un objeto donde listamos los scripts que podemos llamar desde el terminal, el objeto se llama scripts, los que colocamos por defecto son: start (carga la aplicación en una ventana de navegador), build ( empaqueta la aplicación generando un ejecutable sin instalador) y dist (que es la que genera a la vez ele ejecutable sin instalación y el instalador)

«scripts»: {
«start»: «electron .»,
«build»: «electron-builder –dir»,
«dist»: «electron-builder»,
},

El objeto autor donde le indicamos el nombre y el correo, ademas otra propiedad homepage que indica la web del proyecto y la licencia con la que la distribuimos.

"author": {    "name": "pacocontreras",    "email": "buzon@pacocontreras.com"  }, 
"homepage": "http://wwww.pacocontreras.com", 
"license": "MIT",

A continuación generamos un objeto llamado build con las indicaciones para el empaquetado de la aplicación:

"build": {

El nombre de la aplicación:

"appId": "prueba",

Si activamos asar se comprimen en un archivo asar los contenidos de la aplicación, esto no permite sobre escribir los contenidos ni crear archivos dentro en el funcionamiento de la aplicación:

"asar": false,

El files le incicamos que archivos no queremos que incluya en el empaquetado, bien archivos o carpetas con todo su contenido:

"files": [  "!.gitignore",  "!src/less"  ],

Para la plataforma Apple tenemos la entrada mac en la que le indicamos la categoría, el target o tipo de instalador, en este caso le indicamos que sea en zip y arquitectura 64bits, podemos decirle que lo haga en dmg, eso si en ese formato luego da problemas al sobre escribir archivos de la aplicación, también le indicamos el icono icns que queremos que use:

"mac": {      
"category": "public.app-category.utilities", "target": [ {          "target": "zip", "arch": "x64" } ],     
"icon": "src/icons/icon.icns"   
},

Para la plataforma Linux le indicamos el target o formato, en este caso le indicamos deb también le podemos pedir AppImage, que no requiere instalación pero que no permite el sobre escribir archivos de la aplicación. Le indicamos también la carpeta en la que estas los iconos en formato png y con el tamaño como nombre:

"linux": {      
"target": "deb",      
"icon": "src/icons/png/"    
},

Para la plataforma Windows le indicamos el target en este caso NSIS y donde tiene el icono tipo ico:

"win": {      
"target": "NSIS",      
"icon": "src/icons/icon.ico"   
 } 
 
},

Por último tenemos los objetos donde se listan las dependencias que estamos instalando en la carpeta de la aplicación, en dependencies las que se precisan para el proceso de uso de la aplicación y en devdependencias las que se necesitan para el desarrollo y empaquetado, estos bloque se van rellenando de manera automática conforme instalamos los paquetes:

"dependencies": {},
 "devDependencies": {    
"electron": "^7.1.5",    
"electron-builder": "^21.2.0"  
}

Las librerías usan una codificación para saber la versión y los permisos de actualización de la misma.

Lo primero es el permiso de actualización el signo ~ Permite la actualización solo si se cambia un parche sin variar la versión completa. El signo ^ permite actualizar aunque se haya cambiado toda la utilidad, esto es más peligroso porque puede afectar a la integridad de la aplicación.

Después lleva 3 números separados por puntos que indican la versión: el primero marca un cambio drástico, el segundo indica el añadido de una nueva utilidad y el tercero la aplicación de un parche.

Puedes descargar un zip con el contenido base de la aplicación de prueba.


El artículo anterior fué la introducción a «Aplicaciones de escritorio con Electron» y el siguiente artículo «Electron Comunicación entre el back y el front».

Compartir