Um MVC em uma aplicação desktop com Electron.js
Há um tempo, encarei o desafio de criar uma aplicação desktop. Juntamente com meus colegas da faculdade, fizemos toda a análise de requisitos, modelagem do sistema e, onde mais bati cabeça, a arquitetura. Qual arquitetura implementar fora da web?
Logo me deparei com aquela sopa de letrinhas: MVC, MVVM, MVP, Clean Architecture, 😵💫
Qual seguir? Obviamente, comecei pela “mais difícil”, Clean Arch. Era um canhão para matar uma formiga—equipe inexperiente e, o principal problema, como conectar a UI aos dados. Vi que o MVVM era muito utilizado nesse tipo de app, mas, novamente, a camada que liga a UI aos dados (ou front-end ao back-end, como você quiser chamar) adicionava muita complexidade para a equipe. Pois, implementar alguns padrões como Observers e Mediator com JavaScript não seria nada simples. No fim, optei pelo MVC. Vamos à implementação.
Estruturando o MVC 😎
Como o Electron.js nos permite usar ferramentas que utilizamos na web, optei por React no front-end e, no back-end, nenhum framework (logo você vai entender o motivo).
Mas quem vai interligar a view aos controllers no back-end?
Processos no ElectronJS 🤖
O Electron combina três elementos principais:
- Chromium → Responsável por renderizar a interface da aplicação (como um navegador).
- Node.js → Permite acessar recursos do sistema operacional, como arquivos, processos e notificações.
E ele funciona com dois processos principais:
- Processo Principal (Main Process) → Controla a aplicação, janelas e interações com o sistema operacional.
- Processo de Renderização (Renderer Process) → Responsável pela interface gráfica, como as páginas HTML exibidas ao usuário.
Construindo uma API Request-Response 😶🌫️
Para fazer esses processos conversarem, usamos Inter-process communication (IPC). Vamos dar uma olhada na estrutura do projeto, onde Main é o nosso Back-end, Preload é a api e Renderer é o front-end:
1. Endpoints
Vamos ver alguns endpoints da feature de produtos na nossa Router.js. Antes, dois apontamentos:
- Sim, os dados estão sendo armazenados em memória.
- O código está o mais simples possível para que nossos colegas deem os primeiros passos na programação. O intuito é entender o MVC.
O ipcMain é o interprocesso do “lado Node.js” que escuta os eventos. Aqui, adotei o padrão feature:use-case para os endpoints. Simples, não é?
2. API
Aqui está nossa interface que cria o contrato entre o front e o back. Na pasta preload, temos:
Bem simples, certo? Como mencionei antes, adotei o padrão feature:use-case. Devemos nos atentar ao ipcRenderer.invoke()
, sempre seguindo nosso padrão estabelecido, pois no back-end e front-end usaremos da mesma forma.
3. FRONT-END
Agora, na feature do Caixa, no arquivo sliceCaixa.js
, chamamos nossa API:
Aqui é um pouco diferente, mas assim minimizamos erros nos endpoints. Através do objeto window, acessamos a nossa renderer; como primeiro parâmetro, usamos 'api' e, em seguida, vamos acessando cada endpoint.
Então foi isso! Essa é apenas uma solução entre tantas outras, mas foi a que melhor se adequou ao contexto da minha equipe e do projeto. Salva aí para consultas futuras! 🚀
Projeto:link do projeto 👾