Creazione di app desktop con Electron e Vue
Pubblicato: 2022-03-10JavaScript era noto come il linguaggio per la creazione di siti Web e applicazioni Web, in particolare con alcuni dei suoi framework come React, Vue e Angular, ma nel tempo (già nel 2009) è diventato possibile che JavaScript venisse eseguito al di fuori del browser con il comparsa di Node.js, un ambiente di runtime JavaScript multipiattaforma open source che esegue codice JavaScript al di fuori di un browser web. Ciò ha portato alla possibilità di utilizzare JavaScript per molto di più delle semplici applicazioni Web, e una delle quali è la creazione di applicazioni desktop utilizzando Electron.js.
Electron ti consente di creare applicazioni desktop con JavaScript puro fornendo un runtime con ricche API native (sistema operativo). Puoi vederlo come una variante del runtime Node.js incentrato sulle applicazioni desktop anziché sui server Web.
In questo tutorial, impareremo come creare applicazioni desktop utilizzando Electron, impareremo anche come utilizzare Vuejs per creare applicazioni Electron.
Nota : per seguire questo tutorial è richiesta una conoscenza di base di Vue.js e della Vue CLI. Tutto il codice utilizzato in questo tutorial può essere trovato sul mio GitHub. Sentiti libero di clonare e giocarci!
Cosa sono le applicazioni desktop?
Le applicazioni desktop sono applicazioni che funzionano in modo autonomo su computer desktop o laptop. Sono applicazioni che svolgono compiti specifici e sono installate esclusivamente per questo scopo.
Un esempio di applicazione desktop è Microsoft Word, che viene utilizzato per creare e digitare documenti. Altri esempi di applicazioni desktop comuni sono i browser Web, Visual Studio Code e Adobe Photoshop. Le applicazioni desktop sono diverse dalle applicazioni Web perché è necessario installare l'applicazione desktop per potervi accedere e utilizzarla e, a volte, non hanno bisogno dell'accesso a Internet per funzionare. Le app Web, d'altra parte, sono accessibili semplicemente visitando l'URL su cui è ospitata un'app di questo tipo e hanno sempre bisogno dell'accesso a Internet prima di potervi accedere.
Esempi di framework utilizzati nella creazione di app desktop includono:
- Giava
Java è un linguaggio di programmazione generico basato su classi, orientato agli oggetti e progettato per avere il minor numero possibile di dipendenze di implementazione. Ha lo scopo di consentire agli sviluppatori di applicazioni di scrivere una volta, eseguire ovunque (WORA), il che significa che il codice Java compilato può essere eseguito su tutte le piattaforme che supportano Java senza la necessità di ricompilazione. - Java FX
Secondo la loro documentazione ufficiale, si tratta di una piattaforma applicativa client open source di nuova generazione per sistemi desktop, mobili e embedded basati su Java. - C#
C# è un linguaggio di programmazione multiparadigma per uso generico che comprende discipline di programmazione di tipizzazione forte, con ambito lessicale, imperativo, dichiarativo, funzionale, generico, orientato agli oggetti e ai componenti. - .NETTO
.NET è una piattaforma di sviluppo open source gratuita, multipiattaforma per la creazione di diversi tipi di applicazioni. Con .NET puoi utilizzare più lingue, editor e librerie per creare per Web, dispositivi mobili, desktop, giochi e IoT.
Cos'è l'elettrone?
Electron è un framework open source per la creazione di applicazioni desktop. In precedenza era noto come "Atom shell" ed è sviluppato e mantenuto da GitHub. Ti consente di scrivere applicazioni desktop multipiattaforma utilizzando HTML, CSS e JavaScript. Ciò significa che puoi creare applicazioni desktop per Windows, MacOS e altre piattaforme utilizzando una base di codice. È basato su Node.js e Chromium. Esempi di applicazioni create con Electron includono il popolare editor Atom, Visual Studio Code, Wordpress per desktop e Slack.
Installazione
Puoi installare Electron nel tuo progetto usando NPM:
npm install electron --save-dev
Puoi anche installarlo a livello globale se lavorerai molto con le app di elettroni usando questo comando:
npm install electron -g
Creazione di app Vuejs per desktop con Electron
Se hai familiarità con la creazione di applicazioni Web utilizzando Vuejs, è possibile creare applicazioni desktop utilizzando Vuejs. Tutto ciò di cui hai bisogno è Vue CLI Plugin Electron Builder.
Il plug-in CLI Vue Electron Builder
Questo strumento ti consente di creare app Vue per desktop con Electron, ciò significa che fa funzionare la tua applicazione Vue come un'app di elettroni. Ciò significa che la tua applicazione Vue, che probabilmente è un'applicazione Web, può essere estesa per funzionare in ambienti desktop senza la necessità di creare un'applicazione desktop separata in un altro framework. Ciò offre agli sviluppatori Vue la possibilità e il potere di andare oltre il Web. Andando avanti, puoi lavorare sull'idea che hai e offrire agli utenti un'opzione per l'applicazione desktop, che può essere eseguita su Windows, macOS e Linux.
Per vederlo in azione, creeremo un'app News utilizzando l'API News. L'applicazione fornirà i titoli delle ultime notizie e ti consentirà di cercare articoli da fonti di notizie e blog in tutto il Web con la loro API. Tutto ciò di cui hai bisogno per iniziare con loro è la tua chiave API personale che può essere ottenuta da qui.
Creeremo una semplice app che offre quanto segue:
- Una pagina che mostra i titoli più importanti e quelli più importanti di un Paese selezionato con l'opzione di scegliere un Paese utilizzando l'endpoint
/top-headlines
. News API fornisce notizie da un elenco di paesi supportati, trova l'elenco qui. - Notizie da una categoria selezionata utilizzando una combinazione del loro endpoint
/everything
e un parametro di queryq
con il quale specificheremo la nostra categoria.
Dopo aver ottenuto la tua chiave API, possiamo creare la nostra applicazione utilizzando la Vue CLI. Assicurati di avere la Vue CLI installata sul tuo sistema, in caso contrario installala usando questo comando:
npm install -g @vue/cli # OR yarn global add @vue/cli
Una volta fatto, crea la tua app News utilizzando la CLI:
vue create news-app
Recupereremo i dati dall'API News utilizzando Axios per questo tutorial, ma puoi utilizzare qualsiasi alternativa con cui ti senti più a tuo agio. È possibile installare Axios utilizzando uno dei seguenti comandi:
//NPM npm install axios // YARN yarn add axios
Il passaggio successivo sarebbe configurare un'istanza Axios per la configurazione globale nella nostra applicazione. Creeremo una cartella dei plugin nella cartella src dove creeremo questo file axios.js . Dopo aver creato il file, aggiungi le seguenti righe di codice:
import axios from "axios"; let baseURL = `https://newsapi.org/v2`; let apiKey = process.env.VUE_APP_APIKEY; const instance = axios.create({ baseURL: baseURL, timeout: 30000, headers: { "X-Api-Key": apiKey, }, }); export default instance;
Qui, definiamo il nostro baseURL
e apiKey
che abbiamo ottenuto dall'API News e lo passiamo a una nuova istanza di Axios. Questa istanza accetta baseURL
e apiKey
insieme a una proprietà di timeout
. News API richiede che tu aggiunga la tua chiave API quando effettui una richiesta alla loro API e offre 3 modi per allegarla alla tua richiesta, ma qui la stiamo aggiungendo alla proprietà X-Api-Key
dell'intestazione dopo di che esportiamo l' instance
. Fatto ciò, ora possiamo utilizzare questa configurazione per tutte le nostre richieste Axios nella nostra app.
Al termine, puoi aggiungere il builder Plugin Electron con la CLI usando questo comando:
vue add electron-builder
Ti verrà chiesto di selezionare la tua versione di Electron preferita, ho selezionato la versione 9.0.0
perché è l'ultima versione di Electron (al momento della scrittura).
Al termine, ora puoi servire la tua applicazione usando questo comando:
Using Yarn(strongly recommended) yarn electron:serve OR NPM npm run electron:serve
Ci vorrà del tempo per compilare e servire la tua app. Al termine, la tua applicazione si aprirà sul tuo sistema, dovrebbe assomigliare a questo:
Se chiudi gli strumenti di sviluppo della tua app, dovrebbe apparire così:
Questo plug-in di elettroni è super utile e facile da usare perché ogni parte dello sviluppo di questa app funziona allo stesso modo di un'app Vue. Ciò significa che puoi avere una base di codice sia per l'applicazione Web che per l'app desktop. La nostra app sarà composta da tre parti:
- Una pagina di destinazione che mostra le notizie più importanti da un paese scelto a caso.
- Una pagina per visualizzare le notizie principali dal paese scelto dall'utente.
- Una pagina che visualizza le notizie principali da una categoria selezionata dall'utente.
Per questo, avremo bisogno di un componente di intestazione per tutti i nostri collegamenti di navigazione. Quindi creiamo un file nella cartella dei componenti e lo chiamiamo header.vue , quindi aggiungiamo le seguenti righe di codice:
<template> <header class="header"> <div class="logo"> <div class="logo__container"> <img src="../assets/logo.png" alt="News app logo" class="logo__image" /> </div> <h1>News App</h1> </div> <nav class="nav"> <h4 class="nav__link"> <router-link to="/home">Home</router-link> </h4> <h4 class="nav__link"> <router-link to="/top-news">Top News</router-link> </h4> <h4 class="nav__link"> <router-link to="/categories">News By Category</router-link> </h4> </nav> </header> </template> <script> export default { name: "app-header", }; </script> <style> .header { display: flex; flex-wrap: wrap; justify-content: space-between; } .logo { display: flex; flex-wrap: nowrap; justify-content: space-between; align-items: center; height: 50px; } .logo__container { width: 50px; height: 50px; } .logo__image { max-width: 100%; max-height: 100%; } .nav { display: flex; flex-wrap: wrap; width: 350px; justify-content: space-between; } </style>
Qui creiamo un componente di intestazione che ha il nome e il logo della nostra app (l'immagine può essere trovata sul mio GitHub) insieme a una sezione di navigazione che contiene collegamenti alle altre parti della nostra applicazione. La prossima cosa sarebbe importare questa pagina nella nostra pagina di layout - App.vue in modo da poter vedere la nostra intestazione su ogni pagina.
<template> <div> <app-header /> <router-view /> </div> </template> <script> import appHeader from "@/components/Header.vue"; export default { name: "layout", components: { appHeader, }, }; </script> <style> @import url("https://fonts.googleapis.com/css2?family=Abel&family=Staatliches&display=swap"); html, #app { min-height: 100vh; } #app { font-family: "Abel", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; background-color: #fff; } #app h1 { font-family: "Staatliches", cursive; } a { font-weight: bold; color: #2c3e50; text-decoration: none; } a:hover { text-decoration: underline; } a.router-link-exact-active { color: #42b983; } </style>
Qui, sostituiamo il contenuto predefinito nella sezione del modello con il nostro componente di intestazione appena creato dopo averlo importato e dichiarato nella sezione dello script. Infine, aggiungiamo uno stile per l'intera app nella sezione stile.
Ora, se proviamo a visualizzare la nostra app, dovrebbe apparire così:
Il prossimo passo sarebbe aggiungere contenuto al nostro file Home.vue . Questa pagina ospiterebbe la prima sezione della nostra app; Le migliori notizie da un paese selezionato a caso. Aggiorna il tuo file Home.vue con le seguenti righe di codice:
<template> <section class="home"> <h1>Welcome to News App</h1> <h4>Displaying Top News from {{ countryInfo.name }}</h4> <div class="articles__div" v-if="articles"> <news-card v-for="(article, index) in articles" :key="index" :article="article" ></news-card> </div> </section> </template> <script> import { mapActions, mapState } from "vuex"; import NewsCard from "../components/NewsCard"; export default { data() { return { articles: "", countryInfo: "", }; }, components: { NewsCard, }, mounted() { this.fetchTopNews(); }, computed: { ...mapState(["countries"]), }, methods: { ...mapActions(["getTopNews"]), async fetchTopNews() { let countriesLength = this.countries.length; let countryIndex = Math.floor( Math.random() * (countriesLength - 1) + 1 ); this.countryInfo = this.countries[countryIndex]; let { data } = await this.getTopNews( this.countries[countryIndex].value ); this.articles = data.articles; }, }, }; </script> <style> .articles__div { display: flex; flex-wrap: wrap; justify-content: center; } </style>
Nella sezione script di questo file importiamo mapState
e mapActions
da Vuex, che useremo più avanti in questo file. Importiamo anche un componente NewsCard
(lo creeremo in seguito) che visualizzerebbe tutti i titoli delle notizie in questa pagina. Utilizziamo quindi il metodo fetchTopNews
per recuperare le ultime notizie da un paese selezionato a caso dalla serie di countries
nel nostro negozio. Questo paese viene passato alla nostra azione getTopNews
, questo verrebbe aggiunto a baseURL
come query per un paese come questo baseURL/top-news?country=${randomCountry}
. Una volta fatto, eseguiamo il ciclo di questi dati e li passiamo article
prop del nostro componente Newscard
nella sezione del modello. Abbiamo anche un paragrafo che indica da quale paese provengono le notizie principali.
La prossima cosa sarebbe impostare il nostro componente NewsCard
che visualizzerà queste notizie. Crea un nuovo file all'interno della cartella dei componenti , chiamalo NewsCard.vue e aggiungi le seguenti righe di codice:
<template> <section class="news"> <div class="news__section"> <h1 class="news__title"> <a class="article__link" :href="article.url" target="_blank"> {{ article.title }} </a> </h1> <h3 class="news__author" v-if="article.author">{{ article.author }}</h3> <!-- <p class="article__paragraph">{{ article.description }}</p> --> <h5 class="article__published">{{ new Date(article.publishedAt) }}</h5> </div> <div class="image__container"> <img class="news__img" src="../assets/logo.png" :data-src="article.urlToImage" :alt="article.title" /> </div> </section> </template> <script> export default { name: "news-card", props: { article: Object, }, mounted() { this.lazyLoadImages(); }, methods: { lazyLoadImages() { const images = document.querySelectorAll(".news__img"); const options = { // If the image gets within 50px in the Y axis, start the download. root: null, // Page as root rootMargin: "0px", threshold: 0.1, }; const fetchImage = (url) => { return new Promise((resolve, reject) => { const image = new Image(); image.src = url; image.onload = resolve; image.onerror = reject; }); }; const loadImage = (image) => { const src = image.dataset.src; fetchImage(src).then(() => { image.src = src; }); }; const handleIntersection = (entries) => { entries.forEach((entry) => { if (entry.intersectionRatio > 0) { loadImage(entry.target); } }); }; // The observer for the images on the page const observer = new IntersectionObserver(handleIntersection, options); images.forEach((img) => { observer.observe(img); }); }, }, }; </script> <style> .news { width: 100%; display: flex; flex-direction: row; align-items: flex-start; max-width: 550px; box-shadow: 2px 1px 7px 1px #eee; padding: 20px 5px; box-sizing: border-box; margin: 15px 5px; border-radius: 4px; } .news__section { width: 100%; max-width: 350px; margin-right: 5px; } .news__title { font-size: 15px; text-align: left; margin-top: 0; } .news__author { font-size: 14px; text-align: left; font-weight: normal; } .article__published { text-align: left; } .image__container { width: 100%; max-width: 180px; max-height: 180px; } .news__img { transition: max-width 300ms cubic-bezier(0.4, 0, 1, 1), max-height 300ms cubic-bezier(0.4, 0, 1, 1); max-width: 150px; max-height: 150px; } .news__img:hover { max-width: 180px; max-height: 180px; } .article__link { text-decoration: none; color: inherit; } </style>
Qui, mostriamo i dati passati a questo componente usando l' article
item prop. Abbiamo anche un metodo che carica pigramente le immagini allegate a ciascun articolo. Questo metodo scorre il numero di immagini di articoli che abbiamo e lazy le carica quando diventano visibili. Infine, abbiamo stili mirati a questo componente nella sezione stile.
La prossima cosa sarà allestire il nostro negozio in modo da poter iniziare a ricevere le ultime notizie. Aggiungi le seguenti righe di codice al tuo file index.js :
import Vue from "vue"; import Vuex from "vuex"; import axios from "../plugins/axios"; Vue.use(Vuex); const store = new Vuex.Store({ state: { countries: [{ name: "United States of America", value: "us", }, { name: "Nigeria", value: "ng", }, { name: "Argentina", value: "ar", }, { name: "Canada", value: "ca", }, { name: "South Africa", value: "za", }, ], categories: [ "entertainment", "general", "health", "science", "business", "sports", "technology", ], }, mutations: {}, actions: { async getTopNews(context, country) { let res = await axios({ url: `/top-headlines?country=${country}`, method: "GET", }); return res; }, }, }); export default store;
Stiamo aggiungendo due proprietà al nostro negozio, una di queste proprietà è countries
. Questa proprietà contiene un array di oggetti di paesi. Abbiamo anche le categories
di proprietà; questo contiene una serie di categorie disponibili sull'API News. Il lettore apprezzerà la libertà di visualizzare le notizie più importanti da paesi e categorie specifici; questo sarà necessario anche in più di una parte dell'app ed è per questo che stiamo facendo uso dello store. Nella sezione delle azioni del nostro negozio, abbiamo un metodo getTopNews
che recupera le notizie principali da un paese (questo paese è stato passato dal componente che ha chiamato questa azione).
A questo punto, se apriamo la nostra app, dovremmo vedere la nostra pagina di destinazione che assomiglia a questa:
Il file background.js
Questo file è il punto di ingresso di Electron nella tua app. Controlla tutte le impostazioni simili all'app desktop per questa app. Lo stato predefinito di questo file può essere trovato sul mio GitHub.
In questo file, abbiamo alcune configurazioni predefinite impostate per l'app come l' height
e la width
predefinite per la tua app. Diamo un'occhiata ad alcune delle cose che puoi fare in questo file.
Abilitazione degli strumenti di sviluppo Vuejs
Per impostazione predefinita, hai accesso agli strumenti di sviluppo in Electron ma non è abilitato dopo l'installazione. Questo è il risultato di un bug esistente su Windows 10, quindi se apri il file background.js , troverai del codice commentato con commenti che indicano il motivo per cui sono stati commentati:
// Install Vue Devtools // Devtools extensions are broken in Electron 6.0.0 and greater // See https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/378 for more info // Electron will not launch with Devtools extensions installed on Windows 10 with dark mode // If you are not using Windows 10 dark mode, you may uncomment these lines // In addition, if the linked issue is closed, you can upgrade electron and uncomment these lines // try { // await installVueDevtools() // } catch (e) { // console.error('Vue Devtools failed to install:', e.toString()) // }
Quindi, se non sei interessato da questo bug, puoi rimuovere il commento dal blocco try/catch
e anche cercare installVueDevtools
in questo stesso file (riga 5) e anche decommentarlo. Una volta fatto, la tua app si riavvierà automaticamente e quando controlli i tuoi strumenti di sviluppo, dovresti vedere Vuejs Devtools.
Selezione di un'icona personalizzata per la tua app
Per impostazione predefinita, l'icona Electron è impostata come icona predefinita per la tua app e, la maggior parte delle volte, probabilmente vorrai impostare la tua icona personalizzata. Per fare ciò, sposta l'icona nella cartella pubblica e rinominala in icon.png . La prossima cosa da fare sarebbe aggiungere la dipendenza richiesta, electron-icon-builder
.
Puoi installarlo usando uno dei seguenti comandi:
// With Yarn: yarn add --dev electron-icon-builder // or with NPM: npm install --save-dev electron-icon-builder
Una volta fatto, puoi eseguire questo comando successivo. Convertirà la tua icona in formato Electron e stamperà quanto segue nella tua console una volta terminato.
La prossima cosa sarebbe impostare l'opzione dell'icona nel file background.js . Questa opzione va all'interno dell'opzione BrowserWindow
importata da Electron
. Per fare ciò, aggiorna BrowserWindow
in modo che assomigli a questo:
// Add this to the top of your file /* global __static */ // import path import path from 'path' // Replace win = new BrowserWindow({ width: 800, height: 600 }) // With win = new BrowserWindow({ width: 800, height: 600, icon: path.join(__static, 'icon.png') })
Ora, se eseguiamo yarn run electron:build
e visualizziamo la nostra app, dovremmo vedere l'icona aggiornata utilizzata come icona dell'app ma non cambia durante lo sviluppo. Questo problema aiuta a risolvere una correzione manuale per esso su macOS.
Impostazione del titolo per la tua app
Noterai che il titolo della tua app è impostato sul nome dell'app (app di notizie in questo caso) e dovremo cambiarlo. Per farlo, dobbiamo aggiungere una proprietà title
al metodo BrowserWindow
nel nostro file background.js
come questo:
win = new BrowserWindow({ width: 600, height: 500, title: "News App", icon: path.join(__static, "icon.png"), webPreferences: { // Use pluginOptions.nodeIntegration, leave this alone // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION, }, });
Qui, stiamo impostando il titolo della nostra app su "App di notizie". Ma se il tuo file index.html ha un titolo selezionato o il tuo titolo non cambia in questo, prova ad aggiungere questo codice al tuo file:
win.on("page-title-updated", (event) => event.preventDefault());
Stiamo ascoltando un evento che viene attivato quando il nostro title
viene aggiornato da BrowserWindow
. Quando questo evento viene attivato, stiamo dicendo a Electron di non aggiornare il titolo con quello trovato nel file index.html .
Un'altra cosa che potrebbe valere la pena cambiare è productName
, questo controlla quale nome appare quando passi il mouse sull'icona della tua app o come il tuo computer riconosce l'app. In questo momento, il nome della nostra app è Electron
. Per modificare questo nome in produzione, crea un file vue.config.js e aggiungi le seguenti righe di codice:
module.exports = { pluginOptions: { electronBuilder: { builderOptions: { productName: "News App", }, }, }, };
Qui, definiamo productName
come "App di notizie" in modo che quando eseguiamo il comando build per la nostra app, il nome cambi da "Electron" a "App di notizie".
Costruzione multipiattaforma
Per impostazione predefinita, quando esegui il comando build, l'app che viene creata dipende dalla piattaforma su cui viene eseguita. Ciò significa che se esegui il comando build su Linux, l'app che viene creata sarebbe un'app desktop Linux. Lo stesso vale anche per altre piattaforme (macOS e Windows). Ma Electron viene fornito con l'opzione per specificare una piattaforma (o due piattaforme) che desideri generare. Le opzioni disponibili sono:
-
mac
-
win
-
linux
Quindi, per creare la versione Windows della tua app, esegui il comando seguente:
// NPM npm electron:build -- --win nsis // YARN yarn electron:build --win nsis
Conclusione
L'applicazione completata può essere trovata sul mio GitHub. La documentazione ufficiale di Electron fornisce informazioni e una guida che ti aiuta a personalizzare la tua app desktop come preferisci. Alcune delle cose che ho provato ma non sono incluse in questo tutorial sono:
- Personalizzazione del dock su macOS — https://www.electronjs.org/docs/tutorial/macos-dock.
- Impostazione ridimensionabile, massimizzabile e molti altri — https://github.com/electron/electron/blob/master/docs/api/browser-window.md#new-browserwindowoptions.
Quindi, se stai cercando di fare molto di più con la tua applicazione Electron, i loro documenti ufficiali sono un buon punto di partenza.
Risorse correlate
- Node.jshttps://en.wikipedia.org/wiki/Node.js
- Java (linguaggio di programmazione)https://en.wikipedia.org/wiki/Java_(linguaggio_di programmazione)
- Electron (struttura del software)
- JavaFX 14
- elettronjs
- Documentazione elettronica
- Plugin Vue CLI Generatore di elettroni
- Caricamento pigro di immagini per le prestazioni utilizzando Intersection Observer di Chris Nwamba
- assio
- Iniziare con Axios in Nuxthttps://www.smashingmagazine.com/2020/05/getting-started-axios-nuxt/) di Timi Omoyeni