de Andrew Walsh

Cum să construiți o aplicație Electron Desktop în JavaScript: Multithreading, SQLite, module native și alte puncte comune de durere

Cum sa construiti o aplicatie Electron Desktop in JavaScript Multithreading

Ca cadru pentru dezvoltarea aplicațiilor desktop, Electron are multe de oferit. Oferă acces complet la API-ul și ecosfera Node. Se implementează pe toate sistemele de operare majore (cu o singură bază de cod). Iar cu arhitectura sa bazată pe web, puteți utiliza cele mai recente caracteristici ale CSS pentru a crea interfețe UI avansate.

Există o mulțime de articole care se referă la începerea și funcționarea cu Electron, dar mai puține dedicate utilizării SQLite sau a modului de a face mai multe filetări. Ne vom uita cum să folosim Electron pentru a construi aplicații care gestionează cantități mari de date sau să ruleze o mulțime de sarcini.

În special, vom acoperi:

  • Cum funcționează Electron (pe scurt) și cum arhitectura sa afectează ceea ce putem face
  • Multithreading
  • Folosirea bazelor de date locale precum SQLite sau scrierea în orice fișier din cadrul unei aplicații Electron
  • Module native
  • Câteva trebuie să fie conștienți
  • Ambalarea unei aplicații folosind module native

Cum funcționează Electron – prescurtat

1611199330 993 Cum sa construiti o aplicatie Electron Desktop in JavaScript Multithreading

Merită să repetăm ​​principiile cheie din spatele arhitecturii Electron. O aplicație Electron constă din cel puțin două procese. Firul principal este intrarea în aplicația dvs. și face toată munca necesară pentru a arăta utilizatorilor dvs. procesul (sau procesele) de redare. Nu poate exista decât o singură instanță a procesului principal.

Procesele de redare utilizează Chromium pentru a reda aplicația. Așa cum fiecare filă rulează în propriul proces, la fel și fiecare redare. Acestea sunt încărcate folosind BrowserWindow constructor loadURL , care trebuie să indice un fișier HTML local sau la distanță. Asta înseamnă că singura modalitate de a porni un proces de redare este utilizarea unui fișier HTML ca intrare.

Avertismentele arhitecturii Electron

Simplitatea Electron este unul dintre cele mai mari atuuri ale sale. Procesul dvs. principal face orice configurație necesară, apoi trece un fișier HTML sau URL către procesul de redare. Acest fișier poate face orice poate face o aplicație web obișnuită – și sunteți bine să mergeți de acolo.

Dar faptul că nu poate exista decât un singur proces principal face neclar despre cum să implementăm multithreading. Documentația Electron implică faptul că procesele de redare sunt strict concepute pentru sarcina de redare a interfețelor UI (ceea ce, așa cum vom vedea, nu este adevărat).

Este important să știi asta a face orice lucru din punct de vedere computerizat intens în procesul principal va încetini (sau înghețați) procesele de redare. Este esențial ca orice lucru intens din punct de vedere al calculului să fie mutat de pe firul principal. Cel mai bine este să lăsați doar sarcina de a face tot ce este necesar pentru a porni procesele de redare. Deoarece nu putem face o muncă intensă pe același proces de redare care redă frontend-ul aplicației (deoarece acest lucru va avea impact și pe interfața de utilizare), avem nevoie de o altă abordare.

Multithreading

1611199331 162 Cum sa construiti o aplicatie Electron Desktop in JavaScript Multithreading

Există trei abordări generale ale multithreading-ului în Electron:

  • Folosiți lucrători web
  • Creează noi procese pentru a rula sarcini
  • Rulați procesele de redare (ascunse) ca lucrători

Lucrători web

Deoarece Electron este construit deasupra Chromium, orice se poate face pe un browser poate fi făcut într-un proces de redare. Aceasta înseamnă că puteți utiliza lucrători web pentru a rula sarcini intensive în fire separate. Avantajul acestei abordări este simplitatea și păstrarea izomorfismului cu o aplicație web.

Cu toate acestea, există o avertizare foarte mare – nu puteți utiliza module native. Din punct de vedere tehnic puteți, dar acest lucru o va face face ca aplicația dvs. să se blocheze. Aceasta este o problemă semnificativă, întrucât orice aplicație care are nevoie de multithreading poate fi necesară, de asemenea, să utilizeze module native (cum ar fi nod-sqlite3).

Crearea de noi procese

Electron folosește Node ca runtime, ceea ce înseamnă că aveți acces complet la module încorporate, cum ar fi grup. Noile procese pot fi furnizate pentru a rula sarcini, menținând munca intensivă în afara firului principal.

Problema principală este că, spre deosebire de procesele de redare, procesele copil nu pot utiliza metode din biblioteca Electron. Acest lucru vă obligă să mențineți un canal de comunicare cu procesul principal prin IPC. Procesele de redare pot utiliza modul de la distanță pentru a spune procesului principal să facă sarcini numai principale fără acest pas suplimentar.

O altă problemă este că, dacă utilizați module ES sau caracteristici TC39 ale JavaScript, va trebui să vă asigurați că rulați versiuni transpilate ale scripturilor. De asemenea, va trebui să le includeți în aplicația dvs. ambalată. Această problemă afectează orice aplicație de nod care bifurcă procesele, dar adaugă un alt strat de complexitate procesului de construire. De asemenea, poate deveni dificil atunci când echilibrați cerințele de ambalare a aplicației dvs. cu utilizarea instrumentelor de dezvoltare care utilizează funcții precum reîncărcarea live.

Utilizarea proceselor de redare ca fire de lucru

Procesele de redare sunt tratate în mod convențional ca fiind utilizate pentru a reda interfața dvs. de utilizare. Cu toate acestea, ei nu sunt obligați la această sarcină unică. Acestea pot fi ascunse și rulate în fundal de configurarea steagului spectacolului a trecut la BrowserWindow.

A face acest lucru are multe avantaje. Spre deosebire de lucrătorii web, aveți libertatea de a utiliza module native. Și spre deosebire de procesele bifurcate, puteți utiliza în continuare biblioteca de electroni pentru a spune procesului principal să facă lucruri precum deschiderea unui dialog sau crearea notificărilor sistemului de operare.

O provocare atunci când se utilizează Electron este IPC. Deși este simplu, necesită o cantitate mare de plăci și impune dificultatea depanării unui număr mare de ascultători de evenimente. Este, de asemenea, un alt lucru pe care trebuie să îl testezi pe unitate. Utilizând un proces de redare ca fir de lucru, puteți ocoli acest lucru complet. La fel cum ați face cu un server, puteți asculta pe un port local și puteți primi cereri, permițându-vă să utilizați instrumente precum GraphQL + Reacționează Apollo. De asemenea, puteți utiliza portaluri web pentru comunicarea în timp real. Un alt bonus este că nu este nevoie să utilizați ipcRenderer și vă puteți menține aplicațiile Electron și web izomorfe (dacă doriți să utilizați o bază de cod partajată pentru un desktop și o aplicație web).

Pentru cazuri de utilizare avansate, această abordare poate fi combinată cu clusterizarea pentru a obține cele mai bune din toate lumile. Singurul dezavantaj este că va trebui să furnizați un fișier HTML ca intrare pentru procesele dvs. de redare a lucrătorului (care se simte ca un hack).

Cum se utilizează SQLite (sau orice altceva trebuie să scrieți)

1611199331 460 Cum sa construiti o aplicatie Electron Desktop in JavaScript Multithreading

Există mai multe abordări ale managementului de stat care nu necesită module native. De exemplu, gestionarea întregii stări în contextul unui renderer cu Redux.

Cu toate acestea, dacă trebuie să gestionați cantități mari de date, acest lucru nu va fi suficient. În special, vom analiza cum să utilizați SQLite într-o aplicație Electron.

Pentru a implementa aplicația Electron, va trebui mai întâi să o împachetați. Există o serie de instrumente disponibile pentru a face acest lucru – cel mai popular fiind Constructor de electroni. Electron folosește formatul de arhivă ASAR pentru gruparea aplicației într-un singur fișier necomprimat. Arhivele ASAR sunt doar în citire – ceea ce înseamnă că nu le puteți scrie nicio dată. Aceasta înseamnă că nu vă puteți include baza de date în arhiva ASAR împreună cu restul codului (în generatorul de electroni, aceasta ar fi sub „fișiere”).

În schimb, includeți baza de date în directorul Resurse al pachetului dvs. de electronici. Structura fișierului unei aplicații Electron pachet și unde să vă plasați baza de date poate fi văzută mai jos:

Cum sa construiti o aplicatie Electron Desktop in JavaScript Multithreading

Arhiva ASAR ambalată numită app.asar există în ./Contents/Resources. Puteți plasa baza de date sau orice fișier pe care doriți să îl scrieți, dar să îl includeți în aplicația ambalată, în același director. Acest lucru poate fi realizat cu Electron Builder folosind „extraResurse”Configurație.

O altă abordare este crearea unei baze de date în întregul director. Dar va trebui să țineți cont de ștergerea acestui fișier pe toate platformele dacă utilizatorii decid să dezinstaleze aplicația dvs.

Ambalare cu module native

Marea majoritate a modulelor Node sunt scripturi scrise în JavaScript. Module native sunt module scrise în C ++ care au legături pentru utilizare cu Node. Acestea acționează ca o interfață cu alte biblioteci scrise în C / C ++ și sunt de obicei configurate pentru a compila după instalare.

Ca module de nivel scăzut, acestea trebuie să fie compilate pentru arhitecturi țintă și sisteme de operare. Un modul nat compilat pe o mașină Windows nu va funcționa pe o mașină Linux – chiar dacă un modul obișnuit ar funcționa. Aceasta este o problemă pentru Electron, deoarece în cele din urmă trebuie să împachetăm totul într-un fișier executabil .dmg (OSX), .exe (Windows) sau .deb (Linux).

Aplicațiile electronice care utilizează module native trebuie să fie ambalate pe sistemul pe care îl vizează. Deoarece veți dori să automatizați acest proces într-o conductă CI / CD, va trebui să vă construiți dependențele native înainte de ambalare. Pentru a realiza acest lucru, puteți utiliza un instrument dezvoltat de echipa Electron numit reconstruirea electronilor.

Dacă dezvoltați un proiect non-comercial open source, îl puteți utiliza TravisCI (Linux, OSX) și Appveyor (Windows) pentru a construi, testa și implementa automat aplicația dvs. gratuit.

Configurarea pentru acest lucru poate fi dificilă dacă aveți teste de integrare, deoarece va trebui să instalați anumite dependențe pentru ca testele fără cap să funcționeze. Un exemplu de configurare pentru OSX și Linux cu TravisCI poate fi găsit aiciși un exemplu de configurare Appveyor aici (aceste exemple se bazează pe configurația din electron-react-boilerplate proiect, cu adăugarea OSX și implementare).

Gotchas

Când aplicația dvs. Electron este ambalată, este posibil ca unele proprietăți încorporate ale nodului legate de căi să nu se comporte așa cum v-ați aștepta și nu se vor comporta așa cum fac atunci când rulați binarul predefinit pentru a vă servi aplicația.

Variabile precum __dirname, __filename și metode precum process.cwd nu se vor comporta așa cum era de așteptat într-o aplicație ambalată (consultați problemele aici, aici, și aici). Utilizare app.getAppPath in schimb.

O notă finală despre ambalaj

În timp ce dezvoltați o aplicație Electron, vă recomandăm să utilizați atât producția (difuzarea codului combinat cu binarul preconstruit), cât și dezvoltarea (folosind webpack-dev-server sau webpack-serve pentru a viziona fișierele) moduri.

Pentru a vă păstra sănătatea, creați și serviți pachetele dvs. din același director cu codul sursă. Aceasta înseamnă că, atunci când selectați aceste fișiere pentru ambalare, orice ipoteză privind calea fișierului rămâne consecventă între aceste moduri și pachetul dvs.

Cel puțin, procesul dvs. principal va trebui să indice calea fișierului fișierului HTML al proceselor de redare. Dacă mutați acest fișier într-un alt director, ca parte a procesului de compilare, veți fi forțat să mențineți ipotezele structurii fișierului și acest lucru poate deveni rapid un alt strat de complicație de impozitare pe care trebuie să îl mențineți.

Depanarea problemelor legate de căile de fișiere incorecte într-o aplicație pachet este foarte mult un caz de încercare și eroare.

rezumat

1611199332 277 Cum sa construiti o aplicatie Electron Desktop in JavaScript Multithreading

Există mai multe abordări ale multithreading-ului în Electron. Lucrătorii web sunt convenabili, dar nu au capacitatea de a utiliza module native. Prelucrarea proceselor noi funcționează așa cum ar fi în Node, dar lipsa abilității de a utiliza biblioteca Electron forțează utilizarea IPC pentru sarcini comune și poate deveni rapid complicată. Utilizarea proceselor de redare ca lucrători oferă puterea deplină a tuturor instrumentelor de server Node disponibile ca înlocuitor pentru comunicarea prin IPC, păstrând în același timp accesul la module și metode native din biblioteca de redare Electron.

Întrucât Electron împachetează fișiere într-o arhivă ASAR de numai citire, orice fișier pe care trebuie să-l scriem (cum ar fi o bază de date SQLite) nu poate fi inclus. În schimb, acestea pot fi plasate în directorul Resurse unde vor rămâne în aplicația ambalată.

În cele din urmă, țineți cont de faptul că într-o aplicație ambalată, unele proprietăți ale nodului nu se comportă așa cum vă așteptați. Și, pentru claritate, potriviți structura fișierelor pachetului cu codul sursă.