Criamos um aplicativo de desktop nativo de plataforma cruzada no Angular

angular-nodegui


Como você provavelmente já sabe, o Angular já existe em muitas plataformas:



Bem, é claro, não havia desktop suficiente aqui (não vamos falar sobre o Electron ainda).


Para criar aplicativos de desktop, existem muitas soluções usando modelos, por exemplo, soluções como JavaFx, Qt, WPF. Todos eles, exceto o último, são multiplataforma.


Mas e se quiséssemos usar a estrutura familiar e criar uma aplicação nativa nela? Na verdade, foi o que eu fiz.


Para começar, examinei o que está disponível no momento e o que já pode ter sido feito no Angular.


De fato, dessa maneira, quero mostrar que você pode fazer qualquer coisa no Angular, e eu venho fazendo todo tipo de coisa há vários anos seguidos.

Pesquisar


nó libui


É uma biblioteca de GUI leve e portátil que aproveita os recursos nativos da GUI para cada plataforma suportada. É uma alternativa ao elétron.


Um exemplo simples de aplicação:


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

Sob o capô, ele tem ligantes libui simples. (libui: uma biblioteca GUI portátil para C). Tudo isso está passando pelo node-gyp, um utilitário projetado para compilar extensões nativas para o Node.js. O libui-node inclui mais de 30 componentes prontos, bem, e se você decidir criar algo personalizado de repente, precisará mergulhar no código em C. Além disso, os componentes foram escritos há 2 anos e desde então atualizado. Talvez tudo esteja tão bem que não haja necessidade de fazer alterações, e esses 30 componentes são suficientes para o desenvolvimento, bem, ou ninguém precisa do projeto.


Bem, na verdade, o aplicativo final pode ser assim:


nó libui nó libui


Nativo de prótons e Vuido


E aqui é um pouco mais interessante: nativo de prótons e vuido é o mesmo nó de libui, apenas sob React e Vue. Os wrappers correspondentes são escritos sob os componentes do nó libui. Apesar do número de estrelas no github (9k e 6k), os projetos são abandonados e quase ninguém os utiliza. De tudo o que pude encontrar, essas eram aplicações muito simples. Outro problema que descobri são problemas com a personalização da própria interface do usuário, é impossível fazê-lo no libui, e o autor do projeto está pensando em reescrever tudo no Qt.


O próprio Libui é bastante popular por escrever todos os tipos de encadernações, os entusiastas o arrastaram mesmo em php

O aplicativo final pode ficar assim:


Nativo de próton Nativo de próton


Uma interface bastante chata, sem personalização, então essa opção desapareceu imediatamente.


Ou talvez tomar Qt?


Qt, js, css


Claro que você já ouviu falar sobre o Qt e o fato de que ele pode ser encontrado em qualquer lugar, mas poucos ouviram dizer que agora ele está integrado ao Javascript imediatamente. A QML permite a construção declarativa de interfaces do usuário usando ligadores de propriedades e, assim, expandindo a capacidade dos elementos QML existentes. Obviamente, isso é Javascript mais rigoroso do que na web. Você pode escrever algo semelhante ao ES5 usando objetos QML, mas não terá uma API DOM.


Apenas uma observação rápida, como você escreveria no Qt em 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 *} 

Como pode ser o seu código no 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)) } } 

Esses componentes podem ser criados dinamicamente.


A QML também possui um sistema de tipos grandes, que sem dúvida será útil ao definir tudo isso no Typescript.


Você também pode personalizar facilmente os componentes:


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

Quase CSS, não é?


Tudo o que resta a ser adicionado é o que o Qt pode fazer na maioria das plataformas.


E teríamos o Node.js


Ao pesquisar por “nodejs + qt”, obteremos imediatamente o node-qt , mas imediatamente chama a atenção que o produto está morto há muito tempo e a última vez mostrou sinais de vida há 8 anos.


No entanto, na pesquisa você pode encontrar um projeto muito recente - NodeGui.


NodeGui


Como muitas bibliotecas para Gui, o Qt usa seu loop de eventos / mensagens para processar eventos de widgets. Portanto, quando chamamos condicionalmente app.exec (), o Qt inicia o loop da mensagem e o bloqueia lá. Tudo isso é bom quando há apenas um loop de mensagem em todo o aplicativo. Mas como precisamos usar o Qt com NodeJs, e o último também possui seu próprio loop de eventos, é impossível integrá-los com tanta facilidade. Mas essas decisões já foram tomadas, por exemplo, o mesmo pacote que o Electron ou o yode. Essas soluções têm sua própria peculiaridade, geram pelo menos 2 processos - para o thread principal e para o renderizador. Apesar disso, essa abordagem tem um ganho significativo, sem necessidade de modificar NodeJs ou Chromium.


No caso do NodeGui, a situação é um pouco diferente, existe um processo para tudo e, portanto, não há necessidade de atrapalhar os eventos entre os processos. O Nodejs foi bifurcado por isso - e pequenas melhorias foram feitas nos fichários necessários no Qt. E agora você precisa iniciar o processo não como de costume.node main.js, mas qode main.js. Felizmente, o qode é publicado como um módulo npm no pacote @ nodegui / qode. Para iniciar um mundo simples olá, você precisa instalar mais alguns pacotes, para obter mais detalhes sobre cada sistema operacional que você pode ver no site oficial: https://docs.nodegui.org/docs/guides/getting-started


Por padrão, no nodegui, tudo é um widget, e eles podem ser parafusados ​​em vários modelos. Atualmente, existem 2 tipos de modelos no nodegui: FlexLayout e QGridLayout.


Estilos em Nodegui


No momento, você pode definir estilos para widgets inline e através do styleSheet.


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

Por padrão, o Qt suporta todos os seletores CSS2 ( https://doc.qt.io/qt-5/stylesheet-syntax.html#selector-types )


Também não ocorre sem propriedades personalizadas para componentes de estilo. Felizmente, essas propriedades já estão descritas nas docas do Qt e mastigadas no stackoverflow.


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

Angular


O autor do projeto já implementou o suporte ao react, mas é claro que todos esqueceram a existência do Angular.

Como já foi escrito no começo, o Angular pode fazer a maioria das plataformas, mas até agora não havia plataforma para o desktop. Devido à API Angular bem projetada e estruturada, a implementação do nodegui no Angular se resume a escrever uma plataforma personalizada BrowserDynamic com Renderer e substituí-las no aplicativo.


Mas como tudo isso funciona de dentro para fora?


Temos um main.ts condicional e vamos começar com ele.


O processo de inicialização consiste em duas partes: criando uma plataforma e lançando um módulo de inicialização nela.


 platformBrowserDynamic().bootstrapModule(AppModule); 

Através do createPlatformFactory, podemos criar absolutamente qualquer plataforma que você precisar. Para nós, isso significa que não queremos trabalhar com o DOM usual e, além disso, examinaremos a descrição do esquema de interação de elementos ao trabalhar com a renderização. Mais informações sobre a criação da plataforma podem ser encontradas na fonte.


No módulo inicial, descrevemos qual componente renderizar primeiro. Ao criar uma instância de um componente, Angular chama renderComponent e, associando-o à renderização desejada que recebe, com a instância do componente. Tudo o que o Angular fará em relação à renderização de componentes (criação de elementos, configuração de atributos, assinatura de eventos etc.) passará por esse renderizador. Portanto, precisamos substituir o RendererFactory.


Primeiro, no Renderer, estaremos interessados ​​no método createElement. Nesse método, obtemos o nome da tag e, a partir dela, precisamos criar o componente desejado. Felizmente, nodegui tem um conjunto básico de componentes, que eu cuidadosamente portamos e descrevi como eles serão renderizados dentro da estrutura do Angular, jogando tudo no diretório geral de componentes. Outras ações com componentes padrão também passarão por esse renderizador. Mais detalhes .


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


Para ouvir os eventos no renderizador, o nome do evento é emitido e, para esses componentes, penduramos o eventListener usual.


 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); } 

Eventos de componente são exatamente iguais a Qt, por exemplo, em vez do usual (click)=”clickFunc($event)” você deve escrever (clicked) = ”clickFunc($event)” .


Atualmente, 16 componentes padrão estão disponíveis. Mas se você precisar escrever seu componente personalizado, sempre haverá a oportunidade de fazer isso através do QWidget.


Também foi criado um roteador para tornar nosso aplicativo o mais compatível possível com o Angular.


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

Aplicativo nodegui angular
Aplicativo nodegui angular


aplicação meteorológica
aplicação meteorológica


Eu coleciono em prod


Para criar um aplicativo pronto, o nodegui possui seu próprio empacotador - @nodegui/packer.


O utilitário é muito simples, até agora consiste em 2 equipes.


Npx nodegui-packer - init myapp


Este comando criará uma pasta de empacotamento contendo o modelo. Você pode alterar o conteúdo para adicionar um ícone, alterar o nome, a descrição e outras informações do aplicativo, bem como adicionar as dependências necessárias.


npx nodegui-packer - pacote

Este comando inicia a ferramenta necessária para empacotar (por exemplo, macdeployqt para mac) e empacota as dependências.


Em conclusão


Concluindo, quero comparar os resultados com outras soluções da Web na área de trabalho (resultados do lançamento no Mac OS).


tamanho do download tamanho do download


uso de memória uso de memória



Link para o projeto:
irustm / angular-nodegui
Crie aplicativos de desktop de desempenho, nativos e de plataforma cruzada com Angular. Angular NodeGUI é alimentado por Angular


Informações sobre o projeto:
https://t.me/ngFanatic


Informações sobre meus projetos de código aberto
https://twitter.com/irustm

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


All Articles