Site icon Tosolini.info

Electron: comprendere la struttura di una app

Abbiamo visto cosa è Electron e come si installa. Per poter andare avanti è necessario comprendere come Electron viene strutturato. Non sono delle specifiche rigide, come per altro in pieno stile Javascript, dove il codice e certe strutturazioni sono piuttosto malleabili.

Electron come abbiamo visto è un modulo di Node.Js ed infatti fa uno stretto riferimento ad esso, anzi addirittura può utilizzarne i moduli creati da terzi. Quello che maggiormente si differenzia con Node è l’integrazione di una versione di Chrome al suo interno, che fa le funzioni di un vero e proprio browser benché minimale.

In sostanza Node funge da Server, mentre Chrome funge da Client. Nel gergo di Electron si fa riferimento alla parte Node/server come Main process, mentre la parte del browser viene indicata come Renderer process. E’ bene sapere che può esistere un solo Main, mentre i Render possono essere molteplici.

Questo è quello che riguarda la parte logica, mentre per quella fisica, cioè i file, se avete letto il post sull’installazione, durante la creazione di un nuovo progetto quando il wizard ha chiesto quale è il file di partenza dello stesso, proponendomi index.js l’ho modificato con main.js. Questo per dare una continuità logica e per determinare in modo univoco che quello è il file main.js del Main Process.

La struttura minimale dovrà essere come segue:

tua-app/
  ├── package.json
  ├── main.js
  └── index.html

All’interno di main.js devono obbligatoriamente prendere posto alcune dichiarazioni di base. Per prima cosa la richiesta univoca ad Electron, quindi la dichiarazione di una app e la funzione ready, che indica che il processo Main è pronto ad essere invocato/utilizzato.

// richiedo Electron come variabile non mutabile
const electron = require("electron");
// variabile app gestita da electron
const app = electron.app;
//un metodo per indicare che electron è stato caricato
//e possiamo creare una finestra del browser
//attraverso una funzione chiamata createWindow
app.on('ready', createWindow);

a questo punto dobbiamo creare la finestra, ovvero la parte render con la funzione appena invocata

// carichiamo da electron la funzione per creare una finestra in browser
const BrowserWindow = electron.BrowserWindow
// dichiariamo una variabile globale vuota e modificabile
let mainWindow

function createWindow() {
    //assegniamo alla variabile i parametri per la funzione BrowserWindow
    mainWindow = new BrowserWindow({width:1024, height:800})
    //carico il file index.html
    mainWindow.loadURL(`file://${__dirname}/index.html`)
    //al caricamento apro il tool di sviluppo
    mainWindow.webContents.openDevTools()
    //istruisco cosa fare quando chiudo il programma
    mainWindow.on('closed', function(){
        //ovvero distruggo il contenuto di mainWindow
        mainWindow = null
    })
}

generalmente la parte che abbiamo appena visto viene messa prima della dichiarazione di app.on per non incorrere nel classico errore di “createWindow non trovato o non esiste“. Pongo inoltre l’attenzione ai parametri di loadURL, gli apici che dichiarano file://eccetera non sono i classico apostrofo, ma la virgola richiamata solitamente con ALT+9 per il Mac o ALT+0 per Windows/Linux.

A questo punto alla chiusura del programma la distruzione di mainWindow non basta, ma dobbiamo di fatto distruggere app:

// Terminiamo l'App quando tutte le finestre vengono chiuse.
app.on('window-all-closed', () => {
    // Su macOS è comune che l'applicazione e la barra menù 
    // restano attive finché l'utente non esce espressamente tramite i tasti Cmd + Q
    if (process.platform !== 'darwin') {
      app.quit()
    }
})

Facciamo un recap, il file completo dovrà apparire come segue:

// richiedo Electron come variabile non mutabile
const electron = require('electron')
// variabile app gestita da electron
const app = electron.app

// carichiamo da electron la funzione per creare una finestra in browser
const BrowserWindow = electron.BrowserWindow
// dichiariamo una variabile globale vuota e modificabile
let mainWindow

function createWindow() {
    //assegniamo alla variabile i parametri per la funzione BrowserWindow
    mainWindow = new BrowserWindow({width:1024, height:800})
    //carico il file index.html
    mainWindow.loadURL(`file://${__dirname}/index.html`)
    //al caricamento apro il tool di sviluppo
    mainWindow.webContents.openDevTools()
    //istruisco cosa fare quando chiudo il programma
    mainWindow.on('closed', function(){
        //ovvero distruggo il contenuto di mainWindow
        mainWindow = null
    })
}

//un metodo per indicare che electron è stato caricato
//e possiamo creare una finestra del browser
//attraverso una funzione chiamata createWindow
app.on('ready', createWindow)

// Terminiamo l'App quando tutte le finestre vengono chiuse.
app.on('window-all-closed', () => {
    // Su macOS è comune che l'applicazione e la barra menù 
    // restano attive finché l'utente non esce espressamente tramite i tasti Cmd + Q
    if (process.platform !== 'darwin') {
      app.quit()
    }
})

Non ci resta che creare un file index.html che di fatto è la nostra “home page” dell’applicativo. Un esempio classico è quello dove vengono richiamate le versioni di Node, Chrome ed Electron medesimo:

<!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8">
      <title>Hello World!</title>
    </head>
    <body>
      <h1>Hello World!</h1>
      Stiamo utilizzando Node.js <script>document.write(process.versions.node)</script>,
      Chrome <script>document.write(process.versions.chrome)</script>,
      ed Electron <script>document.write(process.versions.electron)</script>.
    </body>
  </html>

Salvato il tutto se lanciamo il comando npm test (dall’interno della cartella dove è presente il file main.js) vedremo apparire un nuovo programma in esecuzione con una finestra che indica le versioni dei vari programmi. Se vi da errore leggete il messaggio che vi ritorna, electron è molto verboso e indica il punto dove si è guastato; molto probabilmente avete dimenticato qualcosa di veniale, come una parentesi o qualcosa del genere.

Conclusioni.

Questa è sostanzialmente la parte didattica iniziale, infatti il codice può prevedere molte altre ottimizzazioni, ad esempio possiamo dichiarare sin dall’inizio in un unica riga sia electron che browserWindow che app come segue:


const {app, BrowserWindow} = require('electron')

in questo caso non abbiamo dichiarato una variabile immutabile electron, ma abbiamo condensato le dichiarazioni successive direttamente in un unica direttiva, che francamente è anche più leggibile a livello di codice. Ulteriori aggiunte derivanti dalle api di Electron andranno addizionate alle const di questa riga.

Exit mobile version