Electron - Guida rapida

Perché Electron?

Electron consente di creare applicazioni desktop con JavaScript puro fornendo un runtime con ricche API native (sistema operativo).

Ciò non significa che Electron sia un'associazione JavaScript alle librerie dell'interfaccia utente grafica (GUI). Invece, Electron utilizza le pagine web come GUI, quindi puoi anche vederlo come un browser Chromium minimo, controllato da JavaScript. Quindi tutte le app elettroniche sono tecnicamente pagine web in esecuzione in un browser che può sfruttare le API del tuo sistema operativo.

Chi utilizza l'elettrone?

Github ha sviluppato Electron per creare l'editor di testo Atom. Sono stati entrambi open source nel 2014. Electron è utilizzato da molte aziende come Microsoft, Github, Slack, ecc.

Electron è stato utilizzato per creare una serie di app. Di seguito sono riportate alcune app degne di nota:

  • Desktop lento
  • Applicazione desktop Wordpress
  • Codice di Visual Studio
  • Caret Markdown Editor
  • Nylas Email App
  • GitKraken client git

Per iniziare a sviluppare utilizzando Electron, è necessario che siano installati Node e npm (node ​​package manager). Se non li hai già, vai a Configurazione del nodo per installare il nodo sul tuo sistema locale. Conferma che node e npm siano installati eseguendo i seguenti comandi nel tuo terminale.

node --version
npm --version

Il comando precedente genererà il seguente output:

v6.9.1
3.10.8

Ogni volta che creiamo un progetto utilizzando npm, dobbiamo fornire un file package.jsonfile, che contiene tutti i dettagli sul nostro progetto. npm ci rende facile impostare questo file. Impostiamo il nostro progetto di sviluppo.

  • Avvia il tuo terminale / cmd, crea una nuova cartella denominata hello-world e apri quella cartella usando il comando cd.

  • Ora per creare il file package.json usando npm, usa il seguente comando.

npm init
  • Ti chiederà le seguenti informazioni:

Continua a premere Invio e inserisci il tuo nome nel campo "nome dell'autore".

Crea una nuova cartella e aprila usando il comando cd. Ora esegui il seguente comando per installare Electron a livello globale.

$ npm install -g electron-prebuilt

Una volta eseguito, puoi verificare se Electron è installato nel modo giusto eseguendo il seguente comando:

$ electron --version

Dovresti ottenere l'output -

v1.4.13

Ora che abbiamo configurato Electron, passiamo alla creazione della nostra prima app che lo utilizza.

Electron prende un file principale definito nel tuo file package.json e lo esegue. Questo file principale crea finestre dell'applicazione che contengono pagine Web sottoposte a rendering e interazione con la GUI (interfaccia utente grafica) nativa del sistema operativo.

Quando avvii un'applicazione utilizzando Electron, a main processè creato. Questo processo principale è responsabile dell'interazione con la GUI nativa del sistema operativo. Crea la GUI della tua applicazione.

Il solo avvio del processo principale non offre agli utenti dell'applicazione alcuna finestra dell'applicazione. Questi vengono creati dal processo principale nel file principale utilizzando il modulo BrowserWindow . Ogni finestra del browser esegue quindi la propriarenderer process. Il processo di rendering prende un file HTML che fa riferimento ai soliti file CSS, file JavaScript, immagini, ecc. E lo visualizza nella finestra.

Il processo principale può accedere alla GUI nativa tramite moduli disponibili direttamente in Electron. L'applicazione desktop può accedere a tutti i moduli Node come il modulo del file system per la gestione dei file, la richiesta di effettuare chiamate HTTP, ecc.

Differenza tra processi Main e Renderer

Il processo principale crea pagine web creando le istanze BrowserWindow . Ogni istanza BrowserWindow esegue la pagina Web nel proprio processo di rendering. Quando un'istanza BrowserWindow viene distrutta, viene terminato anche il processo di rendering corrispondente.

Il processo principale gestisce tutte le pagine Web e i relativi processi di rendering. Ogni processo di rendering è isolato e si preoccupa solo della pagina web in esecuzione al suo interno.

Abbiamo creato un file package.jsonfile per il nostro progetto. Ora creeremo la nostra prima app desktop utilizzando Electron.

Creare un nuovo file chiamato main.js . Inserisci il seguente codice in esso -

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

let win  

function createWindow() { 
   win = new BrowserWindow({width: 800, height: 600}) 
   win.loadURL(url.format ({ 
      pathname: path.join(__dirname, 'index.html'), 
      protocol: 'file:', 
      slashes: true 
   })) 
}  

app.on('ready', createWindow)

Crea un altro file, questa volta un file HTML chiamato index.html . Inserisci il seguente codice in esso.

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Hello World!</title>
   </head>
   
   <body>
      <h1>Hello World!</h1>
      We are using node <script>document.write(process.versions.node)</script>,
      Chrome <script>document.write(process.versions.chrome)</script>,
      and Electron <script>document.write(process.versions.electron)</script>.
   </body>
</html>

Esegui questa app utilizzando il seguente comando:

$ electron ./main.js

Si aprirà una nuova finestra. Sarà simile al seguente:

Come funziona questa app?

Abbiamo creato un file principale e un file HTML. Il file principale utilizza due moduli: app e BrowserWindow . Il modulo app viene utilizzato per controllare il ciclo di vita degli eventi dell'applicazione mentre il modulo BrowserWindow viene utilizzato per creare e controllare le finestre del browser.

Abbiamo definito una funzione createWindow , dove stiamo creando una nuova BrowserWindow e allegando un URL a questa BrowserWindow. Questo è il file HTML che viene visualizzato e mostrato quando eseguiamo l'app.

Abbiamo utilizzato un processo nativo di oggetti Electron nel nostro file html. Questo oggetto è esteso dall'oggetto del processo Node.js e include tutti i filet=its funzionalità aggiungendone molte altre.

L'interfaccia utente delle app Electron è costruita utilizzando HTML, CSS e JS. Quindi possiamo sfruttare tutti gli strumenti disponibili per lo sviluppo web front-end anche qui. Puoi utilizzare strumenti come Angular, Backbone, React, Bootstrap e Foundation per creare le app.

Puoi usare Bower per gestire queste dipendenze front-end. Installa pergola usando -

$ npm install -g bower

Ora puoi ottenere tutti i framework, le librerie, i plugin, ecc. JS e CSS disponibili usando bower. Ad esempio, per ottenere l'ultima versione stabile di bootstrap, inserisci il seguente comando:

$ bower install bootstrap

Questo scaricherà bootstrap in bower_components . Ora puoi fare riferimento a questa libreria nel tuo HTML. Creiamo una semplice pagina utilizzando queste librerie.

Ora installiamo jquery usando il comando npm -

$ npm install --save jquery

Inoltre, questo sarà richiesto nel nostro file view.js. Abbiamo già una configurazione main.js come segue:

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

app.on('ready', createWindow)

Apri i tuoi index.html file e inserisci il seguente codice in esso -

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Hello World!</title>
      <link rel = "stylesheet" 
         href = "./bower_components/bootstrap/dist/css/bootstrap.min.css" />
   </head>
   
   <body>
      <div class = "container">
         <h1>This page is using Bootstrap and jQuery!</h1>
         <h3 id = "click-counter"></h3>
         <button class = "btn btn-success" id = "countbtn">Click here</button>
         <script src = "./view.js" ></script>
      </div>
   </body>
</html>

Creare view.js e inserisci la logica del contatore dei clic in esso -

let $ = require('jquery')  // jQuery now loaded and assigned to $
let count = 0
$('#click-counter').text(count.toString())
$('#countbtn').on('click', () => {
   count ++ 
   $('#click-counter').text(count)
})

Esegui l'app utilizzando il seguente comando:

$ electron ./main.js

Il comando precedente genererà l'output come nello screenshot seguente:

Puoi creare la tua app nativa proprio come costruisci siti web. Se non desideri che gli utenti siano limitati a una dimensione esatta della finestra, puoi sfruttare il design reattivo e consentire agli utenti di utilizzare la tua app in modo flessibile.

La gestione dei file è una parte molto importante della creazione di un'applicazione desktop. Quasi tutte le app desktop interagiscono con i file.

Creeremo un modulo nella nostra app che prenderà come input, un nome e un indirizzo email. Questo modulo verrà salvato in un file e verrà creato un elenco che lo mostrerà come output.

Configura il tuo processo principale usando il codice seguente in main.js file -

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

app.on('ready', createWindow)

Ora apri il file index.html file e inserisci il seguente codice in esso -

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>File System</title>
      <link rel = "stylesheet" 
         href = "./bower_components/bootstrap/dist/css/bootstrap.min.css" />
      
      <style type = "text/css">
         #contact-list {
            height: 150px;
            overflow-y: auto;
         }
      </style>
   </head>
   
   <body>
      <div class = "container">
         <h1>Enter Names and Email addresses of your contacts</h1>
         <div class = "form-group">
            <label for = "Name">Name</label>
            <input type = "text" name = "Name" value = "" id = "Name" 
               placeholder = "Name" class = "form-control" required>
         </div>
         
         <div class = "form-group">
            <label for = "Email">Email</label>
            <input type = "email" name = "Email" value = "" id = "Email" 
               placeholder = "Email" class = "form-control" required>
         </div>
         
         <div class = "form-group">
            <button class = "btn btn-primary" id = "add-to-list">Add to list!</button>
         </div>
         
         <div id = "contact-list">
            <table class = "table-striped" id = "contact-table">
               <tr>
                  <th class = "col-xs-2">S. No.</th>
                  <th class = "col-xs-4">Name</th>
                  <th class = "col-xs-6">Email</th>
               </tr>
            </table>
         </div>
         
         <script src = "./view.js" ></script>
      </div>
   </body>
</html>

Ora dobbiamo gestire l'evento di addizione. Lo faremo nel nostroview.js file.

Creeremo una funzione loadAndDisplayContacts () che inizialmente caricherà i contatti dal file. Dopo aver creato la funzione loadAndDisplayContacts () , creeremo un gestore di clic sul nostroadd to listpulsante. Ciò aggiungerà la voce sia al file che alla tabella.

Nel tuo file view.js, inserisci il seguente codice:

let $ = require('jquery')
let fs = require('fs')
let filename = 'contacts'
let sno = 0

$('#add-to-list').on('click', () => {
   let name = $('#Name').val()
   let email = $('#Email').val()

   fs.appendFile('contacts', name + ',' + email + '\n')

   addEntry(name, email)
})

function addEntry(name, email) {
   if(name && email) {
      sno++
      let updateString = '<tr><td>'+ sno + '</td><td>'+ name +'</td><td>' 
         + email +'</td></tr>'
      $('#contact-table').append(updateString)
   }
}

function loadAndDisplayContacts() {  
   
   //Check if file exists
   if(fs.existsSync(filename)) {
      let data = fs.readFileSync(filename, 'utf8').split('\n')
      
      data.forEach((contact, index) => {
         let [ name, email ] = contact.split(',')
         addEntry(name, email)
      })
   
   } else {
      console.log("File Doesn\'t Exist. Creating new file.")
      fs.writeFile(filename, '', (err) => {
         if(err)
            console.log(err)
      })
   }
}

loadAndDisplayContacts()

Ora esegui l'applicazione, usando il seguente comando:

$ electron ./main.js

Dopo aver aggiunto alcuni contatti, l'applicazione avrà il seguente aspetto:

Per più fs module API calls, fare riferimento al tutorial del Node File System .

Ora possiamo gestire i file usando Electron. Vedremo come chiamare le finestre di dialogo di salvataggio e apertura (native) per i file nel capitolo delle finestre di dialogo.

Abbiamo usato un modulo nodo, fs, nel capitolo precedente. Vedremo ora alcuni altri moduli del nodo che possiamo usare con Electron.

Modulo OS

Utilizzando il modulo OS, possiamo ottenere molte informazioni sul sistema su cui è in esecuzione la nostra applicazione. Di seguito sono riportati alcuni metodi che aiutano durante la creazione dell'app. Questi metodi ci aiutano a personalizzare le app in base al sistema operativo su cui sono in esecuzione.

Suor n Descrizione della funzione
1

os.userInfo([options])

Il os.userInfo()restituisce informazioni sull'utente attualmente attivo. Queste informazioni possono essere utilizzate per personalizzare l'applicazione per l'utente anche senza chiedere esplicitamente informazioni.

2

os.platform()

Il os.platform()restituisce una stringa che identifica la piattaforma del sistema operativo. Questo può essere utilizzato per personalizzare l'app in base al sistema operativo dell'utente.

3

os.homedir()

Il os.homedir()restituisce la directory home dell'utente corrente come una stringa. Generalmente, le configurazioni di tutti gli utenti risiedono nella directory home dell'utente. Quindi questo può essere utilizzato per lo stesso scopo per la nostra app.

4

os.arch()

Il os.arch()restituisce una stringa che identifica l'architettura della CPU del sistema operativo. Può essere utilizzato quando si esegue su architetture esotiche per adattare l'applicazione per quel sistema.

5

os.EOL

Una costante di stringa che definisce il marcatore di fine riga specifico del sistema operativo. Dovrebbe essere utilizzato ogni volta che si terminano le righe nei file sul sistema operativo host.

Utilizzando lo stesso file main.js e il seguente file HTML, possiamo stampare queste proprietà sullo schermo -

<html>
   <head>
      <title>OS Module</title>
   </head>
   
   <body>
      <script>
         let os = require('os')
         document.write('User Info: ' + JSON.stringify(os.userInfo()) + '<br>' + 
            'Platform: ' + os.platform() + '<br>' + 
            'User home directory: ' +  os.homedir() + '<br>' + 
            'OS Architecture: ' + os.arch() + '<br>')
      </script>
   </body>
</html>

Ora esegui l'app utilizzando il seguente comando:

$ electron ./main.js

Il comando precedente genererà il seguente output:

User Info: {"uid":1000,"gid":1000,"username":"ayushgp","homedir":"/home/ayushgp",
   "shell":"/usr/bin/zsh"}
Platform: linux
User home directory: /home/ayushgp
OS Architecture: x64

Modulo Net

Il modulo net viene utilizzato per il lavoro relativo alla rete nell'app. Possiamo creare sia server che connessioni socket usando questo modulo. Generalmente, l'uso del modulo wrapper da npm è raccomandato rispetto all'uso del modulo net per attività relative alla rete.

Le tabelle seguenti elencano i metodi più utili del modulo:

Suor n Descrizione della funzione
1

net.createServer([options][, connectionListener])

Crea un nuovo server TCP. L'argomento connectionListener viene impostato automaticamente come listener per l'evento "connection".

2

net.createConnection(options[, connectionListener])

Un metodo di fabbrica, che restituisce un nuovo "net.Socket" e si connette all'indirizzo e alla porta forniti.

3

net.Server.listen(port[, host][, backlog][, callback])

Inizia ad accettare le connessioni sulla porta e sull'host specificati. Se l'host viene omesso, il server accetterà le connessioni dirette a qualsiasi indirizzo IPv4.

4

net.Server.close([callback])

Infine viene chiuso quando tutte le connessioni sono terminate e il server emette un evento di "chiusura".

5

net.Socket.connect(port[, host][, connectListener])

Apre la connessione per un dato socket. Se vengono forniti porta e host, il socket verrà aperto come socket TCP.

Il modulo net include anche alcuni altri metodi. Per ottenere un elenco più completo, vedere questo .

Ora, creiamo un'app elettronica che utilizzi il modulo net per creare connessioni al server. Dovremo creare un nuovo file,server.js -

var net = require('net');
var server = net.createServer(function(connection) { 
   console.log('Client Connected');
   
   connection.on('end', function() {
      console.log('client disconnected');
   });
   
   connection.write('Hello World!\r\n');
   connection.pipe(connection);
});

server.listen(8080, function() { 
   console.log('Server running on http://localhost:8080');
});

Utilizzando lo stesso file main.js, sostituire il file HTML con il seguente:

<html>
   <head>
      <title>net Module</title>
   </head>
   
   <body>
      <script>
         var net = require('net');
         var client = net.connect({port: 8080}, function() {
            console.log('Connection established!');  
         });
         
         client.on('data', function(data) {
            document.write(data.toString());
            client.end();
         });
         
         client.on('end', function() { 
            console.log('Disconnected :(');
         });
      </script>
   </body>
</html>

Esegui il server utilizzando il seguente comando:

$ node server.js

Eseguire l'applicazione utilizzando il seguente comando:

$ electron ./main.js

Il comando precedente genererà il seguente output:

Osserva che ci colleghiamo automaticamente al server e anche noi ci disconnettiamo automaticamente.

Abbiamo anche alcuni altri moduli del nodo che possiamo utilizzare direttamente sul front-end utilizzando Electron. L'utilizzo di questi moduli dipende dallo scenario in cui vengono utilizzati.

Electron ci fornisce 2 moduli IPC (Inter Process Communication) chiamati ipcMain e ipcRenderer.

Il ipcMainviene utilizzato per comunicare in modo asincrono dal processo principale ai processi di rendering. Quando viene utilizzato nel processo principale, il modulo gestisce i messaggi asincroni e sincroni inviati da un processo di rendering (pagina web). I messaggi inviati da un renderer verranno emessi in questo modulo.

Il ipcRendererviene utilizzato per comunicare in modo asincrono da un processo di rendering al processo principale. Fornisce alcuni metodi in modo da poter inviare messaggi sincroni e asincroni dal processo di rendering (pagina web) al processo principale. Puoi anche ricevere risposte dal processo principale.

Creeremo un processo principale e un processo di rendering che si invieranno messaggi a vicenda utilizzando i moduli di cui sopra.

Crea un nuovo file chiamato main_process.js con i seguenti contenuti -

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

// Event handler for asynchronous incoming messages
ipcMain.on('asynchronous-message', (event, arg) => {
   console.log(arg)

   // Event emitter for sending asynchronous messages
   event.sender.send('asynchronous-reply', 'async pong')
})

// Event handler for synchronous incoming messages
ipcMain.on('synchronous-message', (event, arg) => {
   console.log(arg) 

   // Synchronous event emmision
   event.returnValue = 'sync pong'
})

app.on('ready', createWindow)

Ora crea un nuovo file index.html file e aggiungi il seguente codice in esso.

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Hello World!</title>
   </head>
   
   <body>
      <script>
         const {ipcRenderer} = require('electron')

         // Synchronous message emmiter and handler
         console.log(ipcRenderer.sendSync('synchronous-message', 'sync ping')) 

         // Async message handler
         ipcRenderer.on('asynchronous-reply', (event, arg) => {
            console.log(arg)
         })

         // Async message sender
         ipcRenderer.send('asynchronous-message', 'async ping')
      </script>
   </body>
</html>

Esegui l'app utilizzando il seguente comando:

$ electron ./main_process.js

Il comando precedente genererà il seguente output:

// On your app console
Sync Pong
Async Pong

// On your terminal where you ran the app
Sync Ping
Async Ping

Si consiglia di non eseguire il calcolo di attività pesanti / bloccanti sul processo di rendering. Utilizzare sempre IPC per delegare queste attività al processo principale. Questo aiuta a mantenere il ritmo della tua applicazione.

È molto importante che qualsiasi app sia di facile utilizzo. Di conseguenza non dovresti creare finestre di dialogo usando le chiamate alert (). Electron fornisce un'interfaccia piuttosto buona per svolgere il compito di creare finestre di dialogo. Diamo un'occhiata a questo.

Electron fornisce a dialog modulo che possiamo utilizzare per visualizzare le finestre di dialogo del sistema nativo per l'apertura e il salvataggio di file, avvisi, ecc.

Passiamo direttamente a un esempio e creiamo un'app per visualizzare semplici file di testo.

Crea un nuovo file main.js e inserisci il seguente codice al suo interno -

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

let win  

function createWindow() { 
   win = new BrowserWindow({width: 800, height: 600}) 
   win.loadURL(url.format ({ 
      pathname: path.join(__dirname, 'index.html'), 
      protocol: 'file:', 
      slashes: true 
   })) 
}  

ipcMain.on('openFile', (event, path) => { 
   const {dialog} = require('electron') 
   const fs = require('fs') 
   dialog.showOpenDialog(function (fileNames) { 
      
      // fileNames is an array that contains all the selected 
      if(fileNames === undefined) { 
         console.log("No file selected"); 
      
      } else { 
         readFile(fileNames[0]); 
      } 
   });
   
   function readFile(filepath) { 
      fs.readFile(filepath, 'utf-8', (err, data) => { 
         
         if(err){ 
            alert("An error ocurred reading the file :" + err.message) 
            return 
         } 
         
         // handle the file content 
         event.sender.send('fileData', data) 
      }) 
   } 
})  
app.on('ready', createWindow)

Questo codice aprirà la finestra di dialogo aperta ogni volta che il nostro processo principale riceve un messaggio "openFile" da un processo di rendering. Questo messaggio reindirizzerà il contenuto del file al processo di rendering. Ora dovremo stampare il contenuto.

Ora crea un nuovo file index.html file con il seguente contenuto -

<!DOCTYPE html> 
<html> 
   <head> 
      <meta charset = "UTF-8"> 
      <title>File read using system dialogs</title> 
   </head> 
   
   <body> 
      <script type = "text/javascript"> 
         const {ipcRenderer} = require('electron') 
         ipcRenderer.send('openFile', () => { 
            console.log("Event sent."); 
         }) 
         
         ipcRenderer.on('fileData', (event, data) => { 
            document.write(data) 
         }) 
      </script> 
   </body> 
</html>

Ora ogni volta che eseguiamo la nostra app, verrà visualizzata una finestra di dialogo aperta nativa come mostrato nello screenshot seguente:

Una volta selezionato un file da visualizzare, il suo contenuto verrà visualizzato nella finestra dell'app -

Questo era solo uno dei quattro dialoghi forniti da Electron. Tuttavia, hanno tutti un utilizzo simile. Una volta che impari a farlo usandoshowOpenDialog, quindi puoi utilizzare una qualsiasi delle altre finestre di dialogo.

Le finestre di dialogo con la stessa funzionalità sono:

  • showSaveDialog ([browserWindow,] opzioni [, callback])
  • showMessageDialog ([browserWindow,] opzioni [, callback])
  • showErrorDialog (titolo, contenuto)

Le app desktop sono dotate di due tipi di menu: il application menu(sulla barra in alto) e un file context menu(menu di scelta rapida). Impareremo come crearli entrambi in questo capitolo.

Useremo due moduli: i moduli Menu e MenuItem . Notare che i moduli Menu e MenuItem sono disponibili solo nel processo principale. Per utilizzare questi moduli nel processo di rendering, è necessario il modulo remoto . Ci imbatteremo in questo quando creeremo un menu contestuale.

Ora, creiamo un nuovo file main.js file per il processo principale -

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

const template = [
   {
      label: 'Edit',
      submenu: [
         {
            role: 'undo'
         },
         {
            role: 'redo'
         },
         {
            type: 'separator'
         },
         {
            role: 'cut'
         },
         {
            role: 'copy'
         },
         {
            role: 'paste'
         }
      ]
   },
   
   {
      label: 'View',
      submenu: [
         {
            role: 'reload'
         },
         {
            role: 'toggledevtools'
         },
         {
            type: 'separator'
         },
         {
            role: 'resetzoom'
         },
         {
            role: 'zoomin'
         },
         {
            role: 'zoomout'
         },
         {
            type: 'separator'
         },
         {
            role: 'togglefullscreen'
         }
      ]
   },
   
   {
      role: 'window',
      submenu: [
         {
            role: 'minimize'
         },
         {
            role: 'close'
         }
      ]
   },
   
   {
      role: 'help',
      submenu: [
         {
            label: 'Learn More'
         }
      ]
   }
]

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
app.on('ready', createWindow)

Stiamo costruendo un menu da un modello qui. Ciò significa che forniamo il menu come JSON alla funzione e lei si occuperà del resto. Ora dobbiamo impostare questo menu come menu dell'applicazione.

Ora crea un file HTML vuoto chiamato index.html ed esegui questa applicazione usando -

$ electron ./main.js

Nella posizione normale dei menu dell'applicazione, vedrai un menu basato sul modello sopra.

Abbiamo creato questo menu dal processo principale. Creiamo ora un menu contestuale per la nostra app. Lo faremo nel nostro file HTML -

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Menus</title>
   </head>
   
   <body>
      <script type = "text/javascript">
         const {remote} = require('electron')
         const {Menu, MenuItem} = remote

         const menu = new Menu()

         // Build menu one item at a time, unlike
         menu.append(new MenuItem ({
            label: 'MenuItem1',
            click() { 
               console.log('item 1 clicked')
            }
         }))
         
         menu.append(new MenuItem({type: 'separator'}))
         menu.append(new MenuItem({label: 'MenuItem2', type: 'checkbox', checked: true}))
         menu.append(new MenuItem ({
            label: 'MenuItem3',
            click() {
               console.log('item 3 clicked')
            }
         }))

         // Prevent default action of right click in chromium. Replace with our menu.
         window.addEventListener('contextmenu', (e) => {
            e.preventDefault()
            menu.popup(remote.getCurrentWindow())
         }, false)
      </script>
   </body>
</html>

Abbiamo importato i moduli Menu e MenuItem utilizzando il modulo remoto; quindi, abbiamo creato un menu e aggiunto le nostre voci di menu una per una. Inoltre, abbiamo impedito l'azione predefinita del clic con il pulsante destro del mouse in Chrome e l'abbiamo sostituita con il nostro menu.

La creazione di menu in Electron è un'operazione molto semplice. Ora puoi collegare i tuoi gestori di eventi a questi elementi e gestire gli eventi in base alle tue esigenze.

La barra delle applicazioni è un menu al di fuori della finestra dell'applicazione. Su MacOS e Ubuntu, si trova nell'angolo in alto a destra dello schermo. Su Windows è nell'angolo in basso a destra. Possiamo creare menu per la nostra applicazione nei vassoi di sistema utilizzando Electron.

Crea un nuovo file main.jsfile e aggiungi il codice seguente. Avere un file png pronto per l'uso per l'icona sulla barra delle applicazioni.

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

app.on('ready', createWindow)

Dopo aver impostato una finestra del browser di base, creeremo un nuovo file index.html file con il seguente contenuto -

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Menus</title>
   </head>
   <body>
      <script type = "text/javascript">
         const {remote} = require('electron')
         const {Tray, Menu} = remote
         const path = require('path')

         let trayIcon = new Tray(path.join('','/home/ayushgp/Desktop/images.png'))

         const trayMenuTemplate = [
            {
               label: 'Empty Application',
               enabled: false
            },
            
            {
               label: 'Settings',
               click: function () {
                  console.log("Clicked on settings")
               }
            },
            
            {
               label: 'Help',
               click: function () {
                  console.log("Clicked on Help")
               }
            }
         ]
         
         let trayMenu = Menu.buildFromTemplate(trayMenuTemplate)
         trayIcon.setContextMenu(trayMenu)
      </script>
   </body>
</html>

Abbiamo creato il vassoio utilizzando il sottomodulo Tray. Abbiamo quindi creato un menu utilizzando un modello e successivamente collegato il menu al nostro oggetto vassoio.

Eseguire l'applicazione utilizzando il seguente comando:

$ electron ./main.js

Quando esegui il comando precedente, controlla la barra delle applicazioni per l'icona che hai utilizzato. Ho usato una faccina sorridente per la mia domanda. Il comando precedente genererà il seguente output:

Electron fornisce API di notifiche native solo per MacOS. Quindi non lo useremo, useremo invece un modulo npm chiamato node-notifier . Ci consente di avvisare gli utenti su Windows, MacOS e Linux.

Installa il modulo node-notifier nella cartella dell'app utilizzando il seguente comando in quella cartella:

$ npm install --save node-notifier

Creiamo ora un'app che abbia un pulsante che genererà una notifica ogni volta che clicchiamo su questo pulsante.

Crea un nuovo file main.js file e inserisci il seguente codice in esso -

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

app.on('ready', createWindow)

Creiamo ora la nostra pagina web e lo script che attiverà la notifica. Crea un nuovo fileindex.html file con il seguente codice -

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Menus</title>
   </head>
   
   <body>
      <button type = "button" id = "notify" name = "button">
         Click here to trigger a notification!</button>
      <script type = "text/javascript">
         const notifier = require('node-notifier')
         const path = require('path');
         
         document.getElementById('notify').onclick = (event) => {
            notifier.notify ({
               title: 'My awesome title',
               message: 'Hello from electron, Mr. User!',
               icon: path.join('','/home/ayushgp/Desktop/images.png'),  // Absolute path 
                  (doesn't work on balloons)
               sound: true,  // Only Notification Center or Windows Toasters
               wait: true    // Wait with callback, until user action is taken 
               against notification
            
            }, function (err, response) {
               // Response is response from notification
            });

            notifier.on('click', function (notifierObject, options) {
               console.log("You clicked on the notification")
            });

            notifier.on('timeout', function (notifierObject, options) {
               console.log("Notification timed out!")
            });
         }
      </script>
   </body>
</html>

Il notify ci permette di passargli un objectwithinformazioni come il titolo, il messaggio, la miniatura, ecc. che ci aiutano a personalizzare la notifica. Possiamo anche impostare alcuni listener di eventi sulla notifica.

Ora, esegui l'app utilizzando il seguente comando:

$ electron ./main.js

Quando fai clic sul pulsante che abbiamo creato, vedrai una notifica nativa dal tuo sistema operativo, come mostrato nella seguente schermata:

Abbiamo anche gestito gli eventi in cui l'utente fa clic sulla notifica o la notifica scade. Questi metodi ci aiutano a rendere l'app più interattiva se è in esecuzione in background.

Il tag webview viene utilizzato per incorporare il contenuto "ospite" come le pagine web nella tua app Electron. Questo contenuto è contenuto nel contenitore webview. Una pagina incorporata all'interno della tua app controlla come verrà visualizzato questo contenuto.

La visualizzazione web viene eseguita in un processo separato rispetto alla tua app. Per garantire la sicurezza da contenuti dannosi, la visualizzazione Web non dispone delle stesse autorizzazioni della pagina Web. Ciò mantiene la tua app al sicuro dal contenuto incorporato. Tutte le interazioni tra la tua app e la pagina incorporata saranno asincrone.

Consideriamo un esempio per comprendere l'incorporamento di una pagina web esterna nella nostra app Electron. Incorporeremo il sito Web tutorialspoint nella nostra app sul lato destro. Crea un nuovo filemain.js file con il seguente contenuto -

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

app.on('ready', createWindow)

Ora che abbiamo impostato il nostro processo principale, creiamo il file HTML che incorporerà il sito Web tutorialspoint. Crea un file chiamato index.html con il seguente contenuto:

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Menus</title>
   </head>
   
   <body>
      <div>
         <div>
            <h2>We have the website embedded below!</h2>
         </div>
         <webview id = "foo" src = "https://www.tutorialspoint.com/" style = 
            "width:400px; height:480px;">
            <div class = "indicator"></div>
         </webview>
      </div>
      
      <script type = "text/javascript">
         // Event handlers for loading events.
         // Use these to handle loading screens, transitions, etc
         onload = () => {
            const webview = document.getElementById('foo')
            const indicator = document.querySelector('.indicator')

            const loadstart = () => {
               indicator.innerText = 'loading...'
            }

            const loadstop = () => {
               indicator.innerText = ''
            }

            webview.addEventListener('did-start-loading', loadstart)
            webview.addEventListener('did-stop-loading', loadstop)
         }
      </script>
   </body>
</html>

Esegui l'app utilizzando il seguente comando:

$ electron ./main.js

Il comando precedente genererà il seguente output:

Il tag webview può essere utilizzato anche per altre risorse. L'elemento webview ha un elenco di eventi che emette elencati nei documenti ufficiali. È possibile utilizzare questi eventi per migliorare la funzionalità a seconda delle cose che si verificano nella visualizzazione Web.

Ogni volta che si incorporano script o altre risorse da Internet, è consigliabile utilizzare webview. Questo è consigliato in quanto offre grandi vantaggi in termini di sicurezza e non ostacola il normale comportamento.

L'acquisizione di audio e video sono caratteristiche importanti se si creano app per la condivisione dello schermo, memo vocali e così via. Sono utili anche se è necessaria un'applicazione per acquisire l'immagine del profilo.

Useremo l' API getUserMedia HTML5 per acquisire flussi audio e video con Electron. Per prima cosa impostiamo il nostro processo principale inmain.js file come segue -

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

let win

// Set the path where recordings will be saved
app.setPath("userData", __dirname + "/saved_recordings")

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

app.on('ready', createWindow)

Ora che abbiamo impostato il nostro processo principale, creiamo il file HTML che catturerà questo contenuto. Crea un file chiamatoindex.html con il seguente contenuto -

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>Audio and Video</title>
   </head>
   
   <body>
      <video autoplay></video>
      <script type = "text/javascript">
         function errorCallback(e) {
            console.log('Error', e)
         }

         navigator.getUserMedia({video: true, audio: true}, (localMediaStream) => {
            var video = document.querySelector('video')
            video.src = window.URL.createObjectURL(localMediaStream)
            video.onloadedmetadata = (e) => {
               // Ready to go. Do some stuff.
            };
         }, errorCallback)
      </script>
   </body>
</html>

Il programma sopra genererà il seguente output:

Ora hai lo streaming sia dalla tua webcam che dal tuo microfono. Puoi inviare questo flusso sulla rete o salvarlo nel formato che preferisci.

Dai un'occhiata alla documentazione MDN per acquisire immagini per ottenere le immagini dalla tua webcam e memorizzarle. Ciò è stato fatto utilizzando l' API getUserMedia HTML5 . È inoltre possibile acquisire il desktop dell'utente utilizzando il modulo desktopCapturer fornito con Electron. Vediamo ora un esempio di come ottenere lo stream dello schermo.

Usa lo stesso file main.js come sopra e modifica il file index.html per avere il seguente contenuto:

desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => {
   if (error) throw error
   for (let i = 0; i < sources.length; ++i) {
      if (sources[i].name === 'Your Window Name here!') {
         navigator.webkitGetUserMedia({
            audio: false,
            video: {
               mandatory: {
                  chromeMediaSource: 'desktop',
                  chromeMediaSourceId: sources[i].id,
                  minWidth: 1280,
                  maxWidth: 1280,
                  minHeight: 720,
                  maxHeight: 720
               }
            }
         }, handleStream, handleError)
         return
      }
   }
})

function handleStream (stream) {
   document.querySelector('video').src = URL.createObjectURL(stream)
}

function handleError (e) {
   console.log(e)
}

Abbiamo utilizzato il modulo desktopCapturer per ottenere le informazioni su ciascuna finestra aperta. Ora puoi catturare gli eventi di una specifica applicazione o dell'intero schermo a seconda del nome che passi a sopraif statement. Questo trasmetterà solo ciò che sta accadendo su quella schermata alla tua app.

Puoi fare riferimento a questa domanda StackOverflow per comprendere l'utilizzo in dettaglio.

In genere abbiamo memorizzato alcune scorciatoie per tutte le app che utilizziamo quotidianamente sul nostro PC. Per rendere le tue applicazioni intuitive e facilmente accessibili all'utente, devi consentire all'utente di utilizzare i collegamenti.

Useremo il modulo globalShortcut per definire le scorciatoie nella nostra app. Nota cheAcceleratorssono stringhe che possono contenere più modificatori e codici chiave, combinati dal carattere +. Questi acceleratori vengono utilizzati per definire le scorciatoie da tastiera in tutta la nostra applicazione.

Consideriamo un esempio e creiamo una scorciatoia. Per questo, seguiremo l'esempio delle finestre di dialogo in cui abbiamo utilizzato la finestra di dialogo Apri per aprire i file. Registreremo un fileCommandOrControl+O collegamento per visualizzare la finestra di dialogo.

Nostro main.jsil codice rimarrà lo stesso di prima. Quindi creane uno nuovomain.js file e inserisci il seguente codice in esso -

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

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

ipcMain.on('openFile', (event, path) => {
   const {dialog} = require('electron')
   const fs = require('fs')
   dialog.showOpenDialog(function (fileNames) {
         
      // fileNames is an array that contains all the selected
      if(fileNames === undefined)
         console.log("No file selected")
      else
         readFile(fileNames[0])
   })

   function readFile(filepath){
      fs.readFile(filepath, 'utf-8', (err, data) => {
         if(err){
            alert("An error ocurred reading the file :" + err.message)
            return
         }
         
         // handle the file content
         event.sender.send('fileData', data)
      })
   }
})

app.on('ready', createWindow)

Questo codice aprirà la finestra di dialogo Apri ogni volta che il nostro processo principale riceve un messaggio "openFile" da un processo di rendering. In precedenza questa finestra di dialogo veniva visualizzata ogni volta che l'app veniva eseguita. Limitiamolo ora ad aprirlo solo quando premiamoCommandOrControl+O.

Ora crea un nuovo file index.html file con il seguente contenuto -

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "UTF-8">
      <title>File read using system dialogs</title>
   </head>
   
   <body>
      <p>Press CTRL/CMD + O to open a file. </p>
      <script type = "text/javascript">
         const {ipcRenderer, remote} = require('electron')
         const {globalShortcut} = remote
         globalShortcut.register('CommandOrControl+O', () => {
            ipcRenderer.send('openFile', () => {
               console.log("Event sent.");
            })
            
            ipcRenderer.on('fileData', (event, data) => {
               document.write(data)
            })
         })
      </script>
   </body>
</html>

Abbiamo registrato una nuova scorciatoia e passato una richiamata che verrà eseguita ogni volta che premiamo questa scorciatoia. Possiamo annullare la registrazione delle scorciatoie come e quando non le richiediamo.

Ora una volta aperta l'app, riceveremo il messaggio per aprire il file utilizzando il collegamento che abbiamo appena definito.

Queste scorciatoie possono essere rese personalizzabili consentendo all'utente di scegliere le proprie scorciatoie per azioni definite.

Le variabili d'ambiente controllano la configurazione e il comportamento dell'applicazione senza modificare il codice. Alcuni comportamenti di Electron sono controllati da variabili di ambiente perché vengono inizializzati prima dei flag della riga di comando e del codice dell'app.

Esistono due tipi di variabili di ambiente codificate in elettroni: Production variables e Development variables.

Variabili di produzione

Le seguenti variabili di ambiente sono destinate all'uso in fase di esecuzione in applicazioni Electron in pacchetto.

Suor n Variabile e descrizione
1

GOOGLE_API_KEY

Electron include una chiave API hardcoded per effettuare richieste al servizio web di geocodifica di Google. Poiché questa chiave API è inclusa in ogni versione di Electron, spesso supera la sua quota di utilizzo.

Per aggirare questo problema, puoi fornire la tua chiave API di Google nell'ambiente. Inserisci il seguente codice nel file del processo principale, prima di aprire qualsiasi finestra del browser che effettuerà richieste di geocodifica:

process.env.GOOGLE_API_KEY = 'YOUR_KEY_HERE'
2

ELECTRON_RUN_AS_NODE

Avvia il processo come un normale processo Node.js.

3

ELECTRON_FORCE_WINDOW_MENU_BAR (Linux Only)

Non utilizzare la barra dei menu globale su Linux.

Variabili di sviluppo

Le seguenti variabili di ambiente sono destinate principalmente a scopi di sviluppo e debug.

Suor n Variabile e descrizione
1

ELECTRON_ENABLE_LOGGING

Stampa la registrazione interna di Chrome sulla console.

2

ELECTRON_ENABLE_STACK_DUMPING

Stampa la traccia dello stack sulla console quando Electron si blocca.

3

ELECTRON_DEFAULT_ERROR_MODE

Mostra la finestra di dialogo di arresto anomalo di Windows quando Electron si blocca.

Per impostare una qualsiasi di queste variabili di ambiente come vera, impostala nella tua console. Ad esempio, se desideri abilitare la registrazione, utilizza i seguenti comandi:

Per Windows

> set ELECTRON_ENABLE_LOGGING=true

Per Linux

$ export ELECTRON_ENABLE_LOGGING=true

Tieni presente che dovrai impostare queste variabili di ambiente ogni volta che riavvii il computer. Se vuoi evitare di farlo, aggiungi queste righe al tuo file.bashrc File.

Abbiamo due processi che eseguono la nostra applicazione: il processo principale e il processo di rendering.

Poiché il processo di rendering è quello in esecuzione nella finestra del browser, possiamo utilizzare Chrome Devtools per eseguirne il debug. Per aprire DevTools, usa la scorciatoia "Ctrl + Shift + I" o il tasto <F12>. Puoi controllare come usare devtools qui .

Quando apri DevTools, la tua app apparirà come quella mostrata nello screenshot seguente:

Debug del processo principale

I DevTools in una finestra del browser Electron possono eseguire il debug solo di JavaScript eseguito in quella finestra (cioè le pagine web). Per eseguire il debug di JavaScript eseguito nel processo principale, sarà necessario utilizzare un debugger esterno e avviare Electron con l' opzione --debug o --debug-brk .

Electron ascolterà i messaggi del protocollo del debugger V8 sulla porta specificata; un debugger esterno dovrà connettersi a questa porta. La porta predefinita è 5858.

Esegui la tua app utilizzando quanto segue:

$ electron --debug = 5858 ./main.js

Ora avrai bisogno di un debugger che supporti il ​​protocollo del debugger V8. È possibile utilizzare VSCode o node-inspector per questo scopo. Ad esempio, seguiamo questi passaggi e configuriamo VSCode per questo scopo. Segui questi passaggi per configurarlo:

Scarica e installa VSCode . Apri il tuo progetto Electron in VSCode.

Aggiungi un file .vscode/launch.json con la seguente configurazione -

{
   "version": "1.0.0",
   "configurations": [
      {
         "name": "Debug Main Process",
         "type": "node",
         "request": "launch",
         "cwd": "${workspaceRoot}",
         "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
         "program": "${workspaceRoot}/main.js"
      }
   ]
}

Note - Per Windows, usa "${workspaceRoot}/node_modules/.bin/electron.cmd" per runtimeExecutable.

Imposta alcuni punti di interruzione in main.jse avvia il debug nella visualizzazione Debug. Quando raggiungi i punti di interruzione, lo schermo avrà un aspetto simile a questo:

Il debugger VSCode è molto potente e ti aiuterà a correggere rapidamente gli errori. Hai anche altre opzioni comenode-inspector per eseguire il debug delle app di elettroni.

Il confezionamento e la distribuzione di app è parte integrante del processo di sviluppo di un'applicazione desktop. Poiché Electron è un framework di sviluppo di applicazioni desktop multipiattaforma, anche il confezionamento e la distribuzione di app per tutte le piattaforme dovrebbero essere un'esperienza senza interruzioni.

La comunità di elettroni ha creato un progetto, electron-packager che si occupa dello stesso per noi. Ci consente di impacchettare e distribuire la nostra app Electron con bundle specifici del sistema operativo (.app, .exe ecc.) Tramite JS o CLI.

Piattaforme supportate

Electron Packager funziona sulle seguenti piattaforme host:

  • Windows (32/64 bit)
  • OS X
  • Linux (x86 / x86_64)

Genera eseguibili / bundle per le seguenti piattaforme di destinazione:

  • Windows (noto anche come win32, sia per 32/64 bit)
  • OS X (noto anche come darwin) / Mac App Store (noto anche come mas)
  • Linux (per architetture x86, x86_64 e armv7l)

Installazione

Installa il packager elettronico usando -

# for use in npm scripts
$ npm install electron-packager --save-dev

# for use from cli
$ npm install electron-packager -g

App per imballaggi

In questa sezione vedremo come eseguire il packager dalla riga di comando. La forma base del comando è:

electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch> [optional flags...]

Questo -

  • Trova o scarica la versione corretta di Electron.

  • Usa quella versione di Electron per creare un'app in <output-folder> / <appname> - <platform> - <arch>.

--platform e --archpuò essere omesso, in due casi. Se specifichi--allverranno invece creati bundle per tutte le combinazioni valide di piattaforme / architetture di destinazione. In caso contrario, verrà creato un unico bundle per la piattaforma / architettura host.

Abbiamo utilizzato le seguenti risorse per saperne di più su Electron. Ci siamo riferiti a questi durante la creazione di questo tutorial.

La risorsa più importante è la documentazione di Electron. La documentazione ha un'ampia copertura di quasi tutte le funzionalità e le peculiarità del framework. Sono abbastanza soli da farsi strada attraverso la creazione di un'app.

Ci sono anche alcuni ottimi esempi di Electron presentati nel repository di app per campioni di elettroni.

Risorse video

App desktop con linguaggi web

Sviluppo rapido di app desktop multipiattaforma utilizzando JavaScript ed Electron

I post del blog

Creazione di un'applicazione desktop con Electron

Costruisci un lettore musicale con React & Electron

Creazione della tua prima app desktop con HTML, JS ed Electron

Crea app per nodi desktop multipiattaforma con Electron