Nous faisons une application de bureau native multiplateforme sur Angular

angular-nodegui


Comme vous le savez probablement déjà, Angular existe déjà sur de nombreuses plateformes:



Eh bien, bien sûr, il n'y avait pas assez de bureau ici (ne parlons pas encore d'Electron).


Pour créer des applications de bureau, il existe de nombreuses solutions utilisant des modèles, par exemple, des solutions telles que JavaFx, Qt, WPF. Tous, sauf le dernier, sont multi-plateformes.


Mais que se passerait-il si nous voulions utiliser le framework familier et y faire une application native? En fait, c'est ce que j'ai fait.


Pour commencer, j'ai examiné ce qui est actuellement disponible et ce qui a peut-être déjà été fait sous Angular.


En fait, de cette façon, je veux montrer que vous pouvez faire n'importe quoi sur Angular, et je fais toutes sortes de choses depuis plusieurs années d'affilée.

Chercher


libui-node


Il s'agit d'une bibliothèque GUI légère et portable qui exploite les fonctionnalités natives de l'interface graphique pour chaque plate-forme prise en charge. Il s'agit d'une alternative à Electron.


Un exemple d'application simple:


const win = new libui.UiWindow('Test window', 800, 600, false); 

Sous le capot, il a de simples classeurs libui. (libui: une bibliothèque GUI portable pour C). Tout cela passe par node-gyp, un utilitaire conçu pour compiler des extensions natives pour Node.js. libui-node comprend plus de 30 composants prêts à l'emploi, et si vous décidez soudainement de créer quelque chose de personnalisé, vous devrez vous plonger dans le code en C.Et en plus, les composants eux-mêmes ont été écrits il y a 2 ans, et depuis lors mis à jour. Peut-être que tout est si bon qu'il n'est pas nécessaire d'apporter des modifications, et ces 30 composants sont suffisants pour le développement, enfin, ou personne n'a besoin du projet du tout.


Eh bien, en fait, l'application terminée peut ressembler à ceci:


libui-node libui-node


Originaire des protons et Vuido


Et ici, c'est un peu plus intéressant, natif du proton et vuido est le même noeud libui, uniquement sous React et Vue. Les wrappers correspondants sont écrits sous les composants de libui-node. Malgré le nombre d'étoiles sur github (9k et 6k), les projets sont abandonnés et presque personne ne les utilise. De tout ce que j'ai pu trouver, ce sont des applications très simples. Un autre problème que j'ai découvert est celui de la personnalisation de l'interface utilisateur elle-même, il est impossible de le faire dans libui, et l'auteur du projet envisage de tout réécrire dans Qt.


Libui lui-même est assez populaire pour écrire toutes sortes de reliures, les amateurs l'ont traîné même en php

L'application terminée peut ressembler à ceci:


Natif du proton Natif du proton


Une interface plutôt ennuyeuse sans personnalisation, donc cette option a disparu immédiatement.


Ou peut-être prendre Qt?


Qt, js, css


Bien sûr, vous avez entendu parler de Qt et du fait qu'il peut être trouvé partout, mais peu de gens ont entendu dire qu'il est désormais intégré à Javascript dès le départ. QML permet la construction déclarative d'interfaces utilisateur à l'aide de liants de propriété et, de ce fait, étend la capacité des éléments QML existants. Bien sûr, c'est Javascript plus rigoureux que sur le web. Vous pouvez écrire quelque chose de similaire à ES5 en utilisant des objets QML, mais vous n'aurez pas d'API DOM.


Juste une petite note, comment écririez-vous en Qt sous C ++:


 #include <QApplication> #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); *// Important * QPushButton hello("Hello world!"); hello.resize(100, 30); hello.show(); return app.exec(); *// Important *} 

À quoi pourrait ressembler votre code en Qml:


 Item { function factorial(a) { a = parseInt(a); if (a <= 0) return 1; else return a * factorial(a - 1); } MouseArea { anchors.fill: parent onClicked: console.log(factorial(10)) } } 

Ces composants peuvent être créés dynamiquement.


QML possède également un grand système de type , qui sera sans aucun doute utile lors de la définition de tout cela dans Typescript.


Vous pouvez également personnaliser facilement les composants:


 Reactangle { id: redRectId width: 50 color: red } 

Presque CSS, n'est-ce pas?


Tout ce qui reste à ajouter est ce que Qt peut faire sur la plupart des plateformes.


Et nous aurions Node.js


Lors de la recherche de «nodejs + qt», nous obtiendrons immédiatement node-qt , mais il attire immédiatement l'attention sur le fait que le produit est mort depuis longtemps, et la dernière fois a montré des signes de vie il y a 8 ans.


Néanmoins, dans la recherche, vous pouvez trouver un projet très récent - NodeGui.


NodeGui


Comme de nombreuses bibliothèques pour Gui, Qt utilise sa boucle événement / message pour traiter les événements des widgets. Par conséquent, lorsque nous appelons conditionnellement app.exec (), Qt démarre la boucle de message et la bloque à cet endroit. Tout cela est bien quand il n'y a qu'une seule boucle de message dans toute l'application. Mais comme nous devons utiliser Qt avec NodeJs, et que ce dernier a également sa propre boucle d'événements, il est impossible de les intégrer aussi facilement. Mais de telles décisions ont déjà été prises, par exemple, le même paquet avec Electron ou yode. Ces solutions ont leur propre particularité, elles soulèvent au moins 2 processus - pour le thread principal et pour le moteur de rendu. Malgré cela, cette approche a un gain important, pas besoin de modifier les NodeJs ou le Chrome.


Dans le cas de NodeGui, la situation est légèrement différente, il y a un processus pour tout, et donc, il n'est pas nécessaire de tâtonner les événements entre les processus. Nodejs a été bifurqué pour cela - et des améliorations mineures ont été apportées aux liants nécessaires dans Qt. Et maintenant, vous devez démarrer le processus non pas comme d'habitude node principal.js, mais qode main.js. Heureusement, qode est publié en tant que module npm dans le package @ nodegui / qode. Afin de démarrer un monde bonjour simple, vous devez installer quelques packages supplémentaires, pour plus de détails sur chaque système d'exploitation, vous pouvez voir sur le site officiel: https://docs.nodegui.org/docs/guides/getting-started


Par défaut, dans nodegui, tout est un widget, et ils peuvent être vissés sur différents modèles. Il existe actuellement 2 types de modèles dans nodegui: FlexLayout et QGridLayout.


Styles à Nodegui


À l'heure actuelle, vous pouvez définir des styles pour les widgets à la fois en ligne et via styleSheet.


 widget.setInlineStyle(`color: green`) view.setStyleSheet(` `#helloLabel { color: red; padding: 10px; } #worldLabel { color: green; padding: 10px; } #rootView { background-color: black; } `); 

Qt prend en charge par défaut tous les sélecteurs CSS2 ( https://doc.qt.io/qt-5/stylesheet-syntax.html#selector-types )


Il ne se passe pas non plus de propriétés personnalisées pour styliser les composants. Heureusement, ces propriétés sont déjà décrites dans les docks de Qt et mordues par stackoverflow.


 *QPushButton* { qproperty-iconsize: 20px 20px; } 

Angulaire


L'auteur du projet a déjà implémenté le support de react, mais bien sûr, tout le monde a oublié l'existence d'Angular.

Comme déjà écrit au début, Angular peut faire la plupart des plates-formes, mais jusqu'à présent, il n'y a pas eu de plate-forme pour le bureau. En raison de l'API Angular bien conçue et structurée, l'implémentation de nodegui pour Angular se résume à écrire une plateforme personnaliséeBrowserDynamic avec Renderer et à les remplacer dans l'application.


Mais comment ça marche de l'intérieur?


Nous avons un main.ts conditionnel, et nous allons commencer avec.


Le processus de démarrage se compose de deux parties: créer une plate-forme et y lancer un module de démarrage.


 platformBrowserDynamic().bootstrapModule(AppModule); 

Grâce à createPlatformFactory, nous pouvons créer absolument n'importe quelle plateforme dont vous avez besoin. Pour nous, cela signifie que nous ne voulons pas travailler avec le DOM habituel, et en plus nous allons passer en revue la description du schéma d'interaction des éléments lorsque nous travaillons avec le rendu. Vous trouverez plus d'informations sur la création de la plateforme dans la source.


Dans le module de démarrage, nous décrivons quel composant rendre en premier. Lors de la création d'une instance d'un composant, Angular appelle renderComponent et, en l'associant au rendu souhaité qu'il reçoit, à cette instance du composant. Tout ce que fera Angular concernant le rendu des composants (création d'éléments, définition d'attributs, abonnement à des événements, etc.) passera par ce rendu. Par conséquent, nous devons remplacer RendererFactory.


Tout d'abord, dans Renderer, nous serons intéressés par la méthode createElement. Dans cette méthode, nous obtenons le nom de la balise, et à partir de là, nous devons créer le composant souhaité. Heureusement, nodegui a un ensemble de composants de base, que j'ai soigneusement porté et décrit comment ils seront rendus dans le cadre d'Angular, jetant tout dans le répertoire général des composants. D'autres actions avec des composants standard passeront également par ce rendu. Plus de détails .


[https://blog.nrwl.io/†(https://blog.nrwl.io/) https://blog.nrwl.io/


Pour écouter les événements dans le rendu, le nom de l'événement est levé et pour ces composants, nous suspendons l'habituel eventListener.


 listen(target: any, eventName: string, callback: (event: any) => boolean | void): () => void { const callbackFunc = (e: NativeEvent) => callback.call(target, e); target.addEventListener(eventName, callbackFunc); return () => target.removeEventListener(eventName, callbackFunc); } 

Les événements de composant sont exactement les mêmes que Qt, par exemple, au lieu de l'habituel (click)=”clickFunc($event)” vous devez écrire (clicked) = ”clickFunc($event)” .


Actuellement, 16 composants standard sont disponibles. Mais si vous avez besoin d'écrire votre composant personnalisé, il y a toujours la possibilité de le faire via QWidget.


Un routeur a également été réalisé pour rendre notre application aussi compatible que possible avec Angular.


 const appRoutes: Routes = [ { path: 'home', component: HomeComponent }, { path: 'about', component: AboutComponent } ]; // AppModule imports ... NodeguiRouterModule.forRoot(appRoutes), 

Application nodegui angulaire
Application nodegui angulaire


application météo
application météo


Nous collectons en prod


Afin de construire une application prête à l'emploi, nodegui a son propre packer - @nodegui/packer.


L'utilitaire est très simple, jusqu'à présent se compose de 2 équipes.


npx nodegui-packer - init myapp


Cette commande créera un dossier d'emballage contenant le modèle. Vous pouvez modifier le contenu pour ajouter une icône, changer le nom, la description et d'autres informations de l'application, ainsi que pour ajouter les dépendances nécessaires.


npx nodegui-packer - pack

Cette commande lance l'outil nécessaire pour l'empaquetage (par exemple, macdeployqt pour mac) et compresse les dépendances.


En conclusion


En conclusion, je veux comparer les résultats avec d'autres solutions Web sur le bureau (résultats du lancement sous Mac OS).


taille de téléchargement taille de téléchargement


utilisation de la mémoire utilisation de la mémoire



Lien vers le projet:
irustm / angular-nodegui
* Créez des applications de bureau performantes, natives et multiplateformes avec Angular. Angular NodeGUI est propulsé par Angular


Informations sur le projet:
https://t.me/ngFanatic


Informations sur mes projets open source
https://twitter.com/irustm

Source: https://habr.com/ru/post/fr480396/


All Articles