{"id":2995,"date":"2020-02-20T13:48:41","date_gmt":"2020-02-20T16:48:41","guid":{"rendered":"https:\/\/www.itexto.com.br\/devkico\/?p=2995"},"modified":"2020-02-20T13:56:41","modified_gmt":"2020-02-20T16:56:41","slug":"uma-aplicacao-desktop-usando-react-e-express-com-electron","status":"publish","type":"post","link":"https:\/\/devkico.itexto.com.br\/?p=2995","title":{"rendered":"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron"},"content":{"rendered":"\n<p>J\u00e1 faz algumas semanas que comecei uma imers\u00e3o em React (e React Native) que tem trazido frutos muito interessantes. Dentre eles a solu\u00e7\u00e3o para um cliente cuja restri\u00e7\u00e3o de infraestrutura \u00e9 exposta no di\u00e1logo a seguir:<\/p>\n\n\n\n<p>_ A gente precisa de uma aplica\u00e7\u00e3o para a nossa equipe de vendas.<br>_ Bacana, aonde voc\u00eas querem hospedar a aplica\u00e7\u00e3o?<br>_ N\u00f3s temos um servidor de banco de dados, e apenas isto.<br>_ Legal, podemos implantar a aplica\u00e7\u00e3o neste servidor?<br>_ N\u00e3o, n\u00f3s s\u00f3 temos acesso ao servidor de banco de dados. <br>_ Pode ser ent\u00e3o uma aplica\u00e7\u00e3o desktop?<br>_ Pode sim, mas no futuro a gente queria que ela servisse de API tamb\u00e9m.<\/p>\n\n\n\n<p>E a\u00ed come\u00e7a a aventura. O cliente realmente s\u00f3 tinha este servidor de banco de dados e nesta m\u00e1quina apenas este SGBD poderia ser acessado. Isto me fez lembrar da \u00e9poca em que programava em Delphi\/VB, na qual as aplica\u00e7\u00f5es eram essencialmente compostas por apenas por dois componentes: o servidor de banco de dados e a aplica\u00e7\u00e3o. O nome deste padr\u00e3o arquitetural \u00e9 &#8220;<a href=\"https:\/\/www.techopedia.com\/definition\/467\/two-tier-architecture\" class=\"rank-math-link\">two-tier architecture<\/a>&#8220;.<\/p>\n\n\n\n<p>Mas resolvi inovar: criei meu pr\u00f3prio padr\u00e3o arquitetural e vou cham\u00e1-lo de &#8220;<em>three-tier on disguise architecture<\/em>&#8221; por raz\u00f5es que voc\u00eas v\u00e3o entender mais a frente.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A solu\u00e7\u00e3o<\/h2>\n\n\n\n<p>Ent\u00e3o tenho uma infraestrutura que deseja ser &#8220;two-tier&#8221; inicialmente (banco de dados e cliente apenas) mas que futuramente ser\u00e1 &#8220;three-tier&#8221;. Para os mais novos, o que \u00e9 uma arquitetura &#8220;<a href=\"https:\/\/www.techopedia.com\/definition\/24649\/three-tier-architecture\" class=\"rank-math-link\">three tier<\/a>&#8220;: \u00e9 aquela composta por tr\u00eas m\u00f3dulos:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>O banco de dados.<\/li><li>Uma camada intermedi\u00e1ria de neg\u00f3cios que interage diretamente com o banco de dados e os clientes (uma API).<\/li><li>O cliente, que normalmente era desktop at\u00e9 o in\u00edcio dos anos 2000, mas que tamb\u00e9m pode ser pensado como um cliente web.<\/li><\/ul>\n\n\n\n<p>Em um primeiro momento, no entanto, na vis\u00e3o macro para o cliente, haver\u00e1 apenas dois m\u00f3dulos na solu\u00e7\u00e3o proposta:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>O cliente desktop que acessa o banco de dados diretamente.<\/li><li>O banco de dados que \u00e9 compartilhado por sua equipe.<\/li><\/ul>\n\n\n\n<p>(&#8220;Cliente desktop que acessa o banco de dados diretamente&#8221; &#8211; estranho para voc\u00ea que \u00e9 novato (menos de 10 anos de experi\u00eancia), mas muito comum para o pessoal que desenvolve aplica\u00e7\u00f5es desktop neste modelo de dois n\u00edveis. \u00c9 o que chamam de &#8220;cliente rico&#8221; (<em>rich client<\/em> se quiser falar &#8220;bonito&#8221;) muitas vezes.)<\/p>\n\n\n\n<p>Muitas vezes o cliente desktop no padr\u00e3o two-tier executa na pr\u00e1tica <strong>stored procedures<\/strong> presentes no pr\u00f3prio SGBD (Sistema Gerenciador de Banco de Dados), fazendo com que assim a l\u00f3gica de neg\u00f3cios fique centralizada, o que \u00e9 uma boa ideia. <\/p>\n\n\n\n<p>Na maioria das vezes, entretanto, os fornecedores optam por incluir todas as regras de neg\u00f3cio no cliente visando com isto maior portabilidade entre diferentes tipos de SGBD. Pro nosso exemplo vamos imaginar que toda a regra de neg\u00f3cio fica no cliente, ok?<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"435\" height=\"222\" src=\"https:\/\/www.itexto.com.br\/devkico\/wp-content\/uploads\/2020\/02\/image.png\" alt=\"\" class=\"wp-image-2996\" srcset=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image.png 435w, https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-300x153.png 300w\" sizes=\"(max-width: 435px) 100vw, 435px\" \/><\/figure><\/div>\n\n\n\n<p>No futuro o cliente gostaria de ter uma API, por que ir\u00e1 existir um servidor dedicado pra tal. A\u00ed sim ter\u00edamos um modelo mais convencional (de acordo com os padr\u00f5es de 2020) e poder\u00edamos passar a um modelo web que do ponto de vista de implanta\u00e7\u00e3o \u00e9 muito mais interessante. <\/p>\n\n\n\n<p>O problema \u00e9 que se implementamos um <em>cliente rico<\/em> ter\u00edamos de futuramente reescrever todas estas regras de neg\u00f3cio na API <em>se usarmos uma abordagem convencional, <strong>o que n\u00e3o \u00e9 o caso desta solu\u00e7\u00e3o.<\/strong><\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">A solu\u00e7\u00e3o t\u00e1 no cliente Desktop<\/h3>\n\n\n\n<p>Nosso cliente desktop usa tr\u00eas tecnologias, duas das quais voc\u00ea ter\u00e1 absoluta liberdade pra trocar, desde que sejam baseadas em Node (uma variante do <em>&#8220;seu carro pode ter qualquer cor desde que seja preto<\/em>&#8221; (Ford)).<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Uma API REST implementada usando Express.js (mas voc\u00ea pode usar qualquer outro framework baseado em Node aqui).<\/li><li>O front-end implementado em React.js (mas voc\u00ea pode usar qualquer outra coisa baseada em JavaScript, HTML e CSS).<\/li><li><a href=\"https:\/\/www.electronjs.org\/\" class=\"rank-math-link\">Electron<\/a> pra encapsular os dois elementos em uma aplica\u00e7\u00e3o desktop.<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Precisamos falar sobre <a href=\"https:\/\/www.electronjs.org\/\" class=\"rank-math-link\">Electron<\/a><\/h4>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/upload.wikimedia.org\/wikipedia\/commons\/9\/91\/Electron_Software_Framework_Logo.svg\" alt=\"Resultado de imagem para electron logo\"\/><figcaption><br><\/figcaption><\/figure><\/div>\n\n\n\n<p>O Electron foi criado pela equipe do Github para a escrita do editor <a href=\"https:\/\/atom.io\" class=\"rank-math-link\">Atom<\/a> e depois foi a base usada para criar o <a href=\"https:\/\/code.visualstudio.com\/\" class=\"rank-math-link\">Visual Studio Code<\/a>. Ele nos permite criar aplica\u00e7\u00f5es <strong>desktop<\/strong> baseadas em JavaScript. Mais especificamente, aplica\u00e7\u00f5es que sejam baseadas em Node, que \u00e9 tamb\u00e9m a base do Electron.<\/p>\n\n\n\n<p>Com isto comecei a pensar. <em>Aplica\u00e7\u00f5es web baseadas em Node&#8230; Ok, eu j\u00e1 vi aplica\u00e7\u00f5es renderizadas do lado servidor&#8230; aplica\u00e7\u00f5es renderizadas do lado servidor&#8230; Angular, Vue e React podem ser renderizados do lado servidor&#8230; Hmm&#8230; eu poderia colocar o acesso ao banco de dados ali, hein, no pr\u00f3prio componente&#8230; Ou ent\u00e3o eu poderia fazer algo  melhor&#8230; por que n\u00e3o iniciar um segundo projeto dentro do pr\u00f3prio Electron que carregasse a API e esta API fosse usada pela minha interface web embarcada no Electron?&#8230;.<\/em><\/p>\n\n\n\n<p><strong>Ser\u00e1 que consigo embarcar meu front-end escrito em React e tamb\u00e9m uma API escrita em Express em um projeto Electron? A resposta \u00e9 SIM, e isto \u00e9 o que vou lhe ensinar neste post.<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Voltando ao cliente e apresentando a solu\u00e7\u00e3o<\/h3>\n\n\n\n<p>Nosso cliente desktop \u00e9 portanto o Electron encapsulando dois componentes:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>O front-end escrito em React (ou qualquer outra tecnologia).<\/li><li>A API escrita em Express.js (ou seu outro framework Node.js de prefer\u00eancia).<\/li><\/ul>\n\n\n\n<p>Ao final nosso projeto ser\u00e1 essencialmente o que ilustro no diagrama a seguir:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"385\" height=\"387\" src=\"https:\/\/www.itexto.com.br\/devkico\/wp-content\/uploads\/2020\/02\/image-1.png\" alt=\"\" class=\"wp-image-2998\" srcset=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-1.png 385w, https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-1-298x300.png 298w, https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-1-150x150.png 150w\" sizes=\"(max-width: 385px) 100vw, 385px\" \/><\/figure><\/div>\n\n\n\n<p>O projeto Electron ir\u00e1 encapsular nossa aplica\u00e7\u00e3o Express.js que, por sua vez, ir\u00e1 servir como conte\u00fado est\u00e1tico o front-end escrito em React, j\u00e1 empacotado para o ambiente de produ\u00e7\u00e3o.<\/p>\n\n\n\n<p>No momento em que a aplica\u00e7\u00e3o Electron \u00e9 carregada, inicia-se automaticamente o processo Node respons\u00e1vel por iniciar o Express.js que, por sua vez, ir\u00e1 servir o nosso front-end para os usu\u00e1rios finais. Esta solu\u00e7\u00e3o tr\u00e1s os seguintes benef\u00edcios:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>J\u00e1 prepara o projeto para o futuro: quando a vers\u00e3o desktop n\u00e3o for mais necess\u00e1ria, basta implantar tanto o m\u00f3dulo API, escrito em React.js quanto o m\u00f3dulo front-end escrito em React para um novo ambiente de produ\u00e7\u00e3o.<\/li><li>N\u00e3o teremos aqui um cliente rico, mas sim um bastante an\u00eamico: todo o acesso ao banco de dados ser\u00e1 feito pela API. Lembra quando disse que este padr\u00e3o arquitetural poderia ser chamado de <em>&#8220;three-tier disguised architecture&#8221;<\/em>? Pois \u00e9: o projeto j\u00e1 nasce como sendo algo implementado em tr\u00eas camadas: a diferen\u00e7a \u00e9 que do ponto de vista do usu\u00e1rio parece ter apenas duas. ;)<\/li><li>Nos permite ter todo o processo de desenvolvimento tal como fazemos em projetos web: a \u00fanica diferen\u00e7a ser\u00e1 o passo final que consistir\u00e1 no empacotamento do projeto como uma aplica\u00e7\u00e3o desktop.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Nossa prova de conceito &#8211; quase pondo a m\u00e3o na massa<\/h2>\n\n\n\n<p>Antes de pormos a m\u00e3o na massa, vou expor aqui uma prova de conceito bem simples. Ela basicamente acessa uma base de dados MySQL externa que cont\u00e9m os posts, tal como no diagrama a seguir:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"597\" height=\"431\" src=\"https:\/\/www.itexto.com.br\/devkico\/wp-content\/uploads\/2020\/02\/image-3.png\" alt=\"\" class=\"wp-image-3001\" srcset=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-3.png 597w, https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-3-300x217.png 300w\" sizes=\"(max-width: 597px) 100vw, 597px\" \/><\/figure><\/div>\n\n\n\n<p>Para este exemplo estou usando como base de dados uma lista de posts do \/dev\/All. A API que implementei apenas lista os \u00faltimos posts, que s\u00e3o apresentados ao usu\u00e1rio de uma forma bem tosca em nossa prova de conceito tal como no print a seguir:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1017\" height=\"895\" src=\"https:\/\/www.itexto.com.br\/devkico\/wp-content\/uploads\/2020\/02\/image-4.png\" alt=\"\" class=\"wp-image-3002\" srcset=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-4.png 1017w, https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-4-300x264.png 300w, https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/image-4-768x676.png 768w\" sizes=\"(max-width: 1017px) 100vw, 1017px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Pondo a m\u00e3o na massa<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Criando a aplica\u00e7\u00e3o Electron<\/h3>\n\n\n\n<p>A parte mais simples consiste na cria\u00e7\u00e3o desta parte do projeto. Voc\u00ea s\u00f3 precisa ter o Node.js (preferencialmente em sua \u00faltima vers\u00e3o) instalado em seu computador. Este passo a passo que irei expor aqui \u00e9 essencialmente o que voc\u00ea encontra no site oficial neste <a href=\"https:\/\/www.electronjs.org\/docs\/tutorial\/first-app\" class=\"rank-math-link\">link<\/a>.<\/p>\n\n\n\n<p>Crie um novo projeto com o nome que quiser usando o comando &#8220;npm init -y&#8221;.<\/p>\n\n\n\n<p>Logo na sequ\u00eancia, crie um arquivo chamado &#8220;index.js&#8221; na ra\u00edz do projeto (voltaremos a ele mais tarde) e, na sequ\u00eancia, instale o electron com o seguinte comando:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">npm install --save-dev electron<\/pre>\n\n\n\n<p>No arquivo package.json vamos realizar pequenas modifica\u00e7\u00f5es: aten\u00e7\u00e3o para o atributo &#8220;scripts&#8221; e &#8220;main&#8221;.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  \"name\": \"devall\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start\": \"electron .\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"electron\": \"^8.0.1\",\n    \"electron-builder\": \"^22.3.2\"\n  }\n}<\/pre>\n\n\n\n<p>O script &#8220;start&#8221; ir\u00e1 instruir o Electron a iniciar o projeto para voc\u00ea j\u00e1 em uma janela. N\u00e2o execute o comando &#8220;npm start&#8221; ainda, pois voc\u00ea n\u00e3o colocou o conte\u00fado necess\u00e1rio no index.js, que \u00e9 o ponto de partida do projeto. Por falar nele, segue seu conte\u00fado:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">const {app, BrowserWindow} = require('electron')\n\nfunction createWindow() {\n\n    let win = new BrowserWindow(\n        {width:1200, \n         height:600, \n         webPreferences:{nodeIntegration:true}}\n    )\n    \/\/ win.webContents.openDevTools()\n    win.loadURL('http:\/\/localhost:3000\/')\n    \n    win.focus();\n\n    \n}\n\napp.whenReady().then(createWindow)<\/pre>\n\n\n\n<p> O script apenas ir\u00e1 criar uma janela para n\u00f3s. Mas \u00e9 importante uma breve explica\u00e7\u00e3o apesar deste post n\u00e3o ser um aprofundamento no Electron. A fun\u00e7\u00e3o <em>createWindow<\/em> \u00e9 que faz boa parte da m\u00e1gica acontecer aqui. Nela criamos um objeto do tipo <em>BrowserWindow<\/em> que equivale a uma janela desktop (um navegador embutido pra ser bem franco). Ali definimos sua largura e altura e tamb\u00e9m se ter\u00e1 integra\u00e7\u00e3o com o Node. Neste caso tem de ter, por que iremos embarcar uma aplica\u00e7\u00e3o Express.js neste projeto.<\/p>\n\n\n\n<p>Quando a aplica\u00e7\u00e3o estiver pronta (<em>app.whenReady<\/em>) esta fun\u00e7\u00e3o \u00e9 chamada. Notou que ela manda a janela carregar o endere\u00e7o &#8220;http:\/\/localhost:3000&#8221;? Mais a respeito disto l\u00e1 na frente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Preparando o projeto Express.js<\/h3>\n\n\n\n<p>Crie o projeto Express com a ferramenta de linha de comando do framework (ou ent\u00e3o use o c\u00f3digo fonte que voc\u00ea j\u00e1 tenha). No interior do diret\u00f3rio que cont\u00e9m seu projeto crie um diret\u00f3rio qualquer (chamarei de &#8220;api&#8221; aqui no nosso exemplo) e copie para seu interior o c\u00f3digo fonte do seu projeto React.<\/p>\n\n\n\n<p>Voc\u00ea est\u00e1 com 90% do caminho pronto agora. Vamos ao pequeno detalhe: o modo como iremos servir <strong>o conte\u00fado est\u00e1tico da aplica\u00e7\u00e3o.<\/strong> Dado que seu projeto Express ser\u00e1 executado <strong>no contexto do Electron<\/strong>, o modo como conte\u00fado est\u00e1tico \u00e9 carregado deve ser levemente modificado.<\/p>\n\n\n\n<p>O modo padr\u00e3o como o Express configura conte\u00fado est\u00e1tico \u00e9 tal como no exemplo a seguir, certo?<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">app.use(express.static(path.join(__dirname, 'public')));<\/pre>\n\n\n\n<p>Mude para que fique tal como no exemplo a seguir:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">app.use(express.static(__dirname + '\/public'))<\/pre>\n\n\n\n<p>Voc\u00ea precisar\u00e1 servir a partir do diret\u00f3rio do Electron \u00e9 executado. Esta \u00e9 a grande diferen\u00e7a!<\/p>\n\n\n\n<p>Feito isto seu projeto Express.js est\u00e1 pronto. Implemente seus endpoints nele, conecte-se ao banco de dados, fa\u00e7a o que quiser. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Preparando o projeto React.js<\/h3>\n\n\n\n<p>Sabe o que voc\u00ea precisa fazer com seu c\u00f3digo fonte aqui? Praticamente nada! Apenas realize todas as suas requisi\u00e7\u00f5es REST contra o endere\u00e7o &#8220;localhost:3000&#8221; (ou qualquer outra porta que tenha configurado no seu projeto API).<\/p>\n\n\n\n<p>E como voc\u00ea faz para implantar o projeto no Electron? Simples demais: apenas dois passos.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Execute o build do projeto &#8220;npm run build&#8221;.<\/li><li>Copie o conte\u00fado da pasta &#8220;build&#8221; para a pasta &#8220;public&#8221; do seu projeto Express, j\u00e1 dentro do projeto Electron<\/li><\/ul>\n\n\n\n<p>H\u00e1 mais um detalhe: inclua a propriedade &#8220;homepage&#8221; com o valor &#8220;.\/&#8221; no arquivo package.json do seu projeto. Isto garante que o carregamento do front-end ser\u00e1 a partir deste caminho relativo pra frente quando for construir a solu\u00e7\u00e3o.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Empacotando tudo agora<\/h3>\n\n\n\n<p>Com os tr\u00eas projetos prontos, tudo o que voc\u00ea precisa fazer \u00e9 executar o &#8220;npm install&#8221; dentro do diret\u00f3rio que cont\u00e9m o c\u00f3digo fonte da sua API. Fa\u00e7a o mesmo no diret\u00f3rio externo, isto \u00e9, o diret\u00f3rio do projeto &#8220;Electron&#8221;.<\/p>\n\n\n\n<p>Execute &#8220;npm start&#8221;. Olha l\u00e1 seu projeto em execu\u00e7\u00e3o!<\/p>\n\n\n\n<p>E agora, vamos ao grand finalle: como empacotar o projeto? Voc\u00ea vai precisar gerar um .exe se for Windows ou o equivalente pro Linux e MacOS. Use este projeto aqui: <a href=\"https:\/\/www.electron.build\/\" class=\"rank-math-link\">Electron Build<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Ainda n\u00e3o acabou: <strong>O<\/strong> <strong>detalhe<\/strong> crucial!<\/h4>\n\n\n\n<p>Se voc\u00ea seguiu at\u00e9 agora este guia e foi construindo o projeto, talvez no momento em que iniciou a aplica\u00e7\u00e3o tenha visto uma janela com uma tela em branco, certo? Isto ocorre por que n\u00e3o realizamos a integra\u00e7\u00e3o <strong>de fato<\/strong> com o Express. \u00c9 preciso iniciar a aplica\u00e7\u00e3o. <\/p>\n\n\n\n<p>H\u00e1 diversas maneiras de se fazer isto. Se voc\u00ea criou seu projeto com a <a href=\"https:\/\/expressjs.com\/pt-br\/starter\/generator.html\" class=\"rank-math-link\">ferramenta de linha de comando<\/a> do framework basta executar o arquivo <em>www<\/em> que fica na pasta <em>bin<\/em> do seu projeto Express. Ent\u00e3o, voltando ao arquivo <em>index.js<\/em> que criamos no projeto ELectron, seu in\u00edcio dever\u00e1 ser tal como no exemplo a seguir:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">const {app, BrowserWindow} = require('electron')\n\n\/\/ esta \u00e9 a linha que faz toda a diferen\u00e7a!\nconst express = require('.\/api\/bin\/www');\n\nfunction createWindow() {\n    console.log(express)\n    let win = new BrowserWindow(\n        {width:1200, \n         height:600, \n         webPreferences:{nodeIntegration:true}}\n    )\n    \/\/ win.webContents.openDevTools()\n    win.loadURL('http:\/\/localhost:3000\/')\n    \n    win.focus();\n\n    \n}\n\napp.whenReady().then(createWindow)<\/pre>\n\n\n\n<p>Com isto a aplica\u00e7\u00e3o Express ser\u00e1 carregada antes da janela ser exposta. E notou outra coisa? Como o front-end feito em React \u00e9 carregado pelo Express, este ao ser exposto ao usu\u00e1rio <strong>obrigat\u00f3riamente <\/strong>estar\u00e1 j\u00e1 acessando a API j\u00e1 carregada. Resolvemos dois problemas com um \u00fanico golpe. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Melhorando o projeto<\/h2>\n\n\n\n<p>O guia at\u00e9 aqui te deu o b\u00e1sico pra que voc\u00ea consiga construir uma aplica\u00e7\u00e3o desktop usando React e Node.js. Mas voc\u00ea pode melhorar bastante isto: como a aplica\u00e7\u00e3o usa Node, \u00e9 poss\u00edvel acessar arquivos no computador do usu\u00e1rio, portanto criar configura\u00e7\u00f5es fica muito mais f\u00e1cil.<\/p>\n\n\n\n<p>E lendo a<a href=\"https:\/\/www.electronjs.org\/docs\/\" class=\"rank-math-link\"> documenta\u00e7\u00e3o oficial do Electron<\/a> voc\u00ea ver\u00e1 que \u00e9 poss\u00edvel customizar bastante a aplica\u00e7\u00e3o: incluir um \u00edcone personalizado, mudar o t\u00edtulo da janela principal, expor\/ocultar menus, apresentar o console de depura\u00e7\u00e3o e muito mais.<\/p>\n\n\n\n<p>Voc\u00ea pode ter acesso \u00e0 prova de conceito (observe: \u00e9 uma prova de conceito, n\u00e3o deve ser usada em produ\u00e7\u00e3o sob hip\u00f3tese ALGUMA) que fiz <a href=\"https:\/\/github.com\/itexto\/exemplo-electron-react-nodejs\" class=\"rank-math-link\">neste reposit\u00f3rio do Github<\/a>.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Como usar React (ou qualquer framework web para SPA) e Express para criar aplica\u00e7\u00f5es desktop usando Electron.<\/p>\n","protected":false},"author":1,"featured_media":3004,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[92,91,78,90],"tags":[97,94,96,100,99,95,93,98],"class_list":["post-2995","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-electron","category-express","category-node-js","category-react","tag-desktop","tag-electron","tag-express","tag-front-end","tag-frontend","tag-node-js","tag-react","tag-web"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron - \/dev\/Kico<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/devkico.itexto.com.br\/?p=2995\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron - \/dev\/Kico\" \/>\n<meta property=\"og:description\" content=\"Como usar React (ou qualquer framework web para SPA) e Express para criar aplica\u00e7\u00f5es desktop usando Electron.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/devkico.itexto.com.br\/?p=2995\" \/>\n<meta property=\"og:site_name\" content=\"\/dev\/Kico\" \/>\n<meta property=\"article:published_time\" content=\"2020-02-20T16:48:41+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-02-20T16:56:41+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"1200\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Kico (Henrique Lobo Weissmann)\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@loboweissmann\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kico (Henrique Lobo Weissmann)\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. tempo de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=2995\",\"url\":\"https:\/\/devkico.itexto.com.br\/?p=2995\",\"name\":\"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron - \/dev\/Kico\",\"isPartOf\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=2995#primaryimage\"},\"image\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=2995#primaryimage\"},\"thumbnailUrl\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png\",\"datePublished\":\"2020-02-20T16:48:41+00:00\",\"dateModified\":\"2020-02-20T16:56:41+00:00\",\"author\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7\"},\"breadcrumb\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=2995#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/devkico.itexto.com.br\/?p=2995\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=2995#primaryimage\",\"url\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png\",\"contentUrl\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png\",\"width\":1200,\"height\":1200},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=2995#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/devkico.itexto.com.br\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#website\",\"url\":\"https:\/\/devkico.itexto.com.br\/\",\"name\":\"\/dev\/Kico\",\"description\":\"Desenvolvendo software\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/devkico.itexto.com.br\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7\",\"name\":\"Kico (Henrique Lobo Weissmann)\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g\",\"caption\":\"Kico (Henrique Lobo Weissmann)\"},\"sameAs\":[\"https:\/\/x.com\/loboweissmann\"],\"url\":\"https:\/\/devkico.itexto.com.br\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron - \/dev\/Kico","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/devkico.itexto.com.br\/?p=2995","og_locale":"pt_BR","og_type":"article","og_title":"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron - \/dev\/Kico","og_description":"Como usar React (ou qualquer framework web para SPA) e Express para criar aplica\u00e7\u00f5es desktop usando Electron.","og_url":"https:\/\/devkico.itexto.com.br\/?p=2995","og_site_name":"\/dev\/Kico","article_published_time":"2020-02-20T16:48:41+00:00","article_modified_time":"2020-02-20T16:56:41+00:00","og_image":[{"width":1200,"height":1200,"url":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png","type":"image\/png"}],"author":"Kico (Henrique Lobo Weissmann)","twitter_card":"summary_large_image","twitter_creator":"@loboweissmann","twitter_misc":{"Escrito por":"Kico (Henrique Lobo Weissmann)","Est. tempo de leitura":"12 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/devkico.itexto.com.br\/?p=2995","url":"https:\/\/devkico.itexto.com.br\/?p=2995","name":"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron - \/dev\/Kico","isPartOf":{"@id":"https:\/\/devkico.itexto.com.br\/#website"},"primaryImageOfPage":{"@id":"https:\/\/devkico.itexto.com.br\/?p=2995#primaryimage"},"image":{"@id":"https:\/\/devkico.itexto.com.br\/?p=2995#primaryimage"},"thumbnailUrl":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png","datePublished":"2020-02-20T16:48:41+00:00","dateModified":"2020-02-20T16:56:41+00:00","author":{"@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7"},"breadcrumb":{"@id":"https:\/\/devkico.itexto.com.br\/?p=2995#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/devkico.itexto.com.br\/?p=2995"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/devkico.itexto.com.br\/?p=2995#primaryimage","url":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png","contentUrl":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png","width":1200,"height":1200},{"@type":"BreadcrumbList","@id":"https:\/\/devkico.itexto.com.br\/?p=2995#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/devkico.itexto.com.br\/"},{"@type":"ListItem","position":2,"name":"Uma aplica\u00e7\u00e3o desktop usando React e Express com Electron"}]},{"@type":"WebSite","@id":"https:\/\/devkico.itexto.com.br\/#website","url":"https:\/\/devkico.itexto.com.br\/","name":"\/dev\/Kico","description":"Desenvolvendo software","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/devkico.itexto.com.br\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"pt-BR"},{"@type":"Person","@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7","name":"Kico (Henrique Lobo Weissmann)","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g","caption":"Kico (Henrique Lobo Weissmann)"},"sameAs":["https:\/\/x.com\/loboweissmann"],"url":"https:\/\/devkico.itexto.com.br\/?author=1"}]}},"jetpack_featured_media_url":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2020\/02\/electron_logo.png","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/2995"}],"collection":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2995"}],"version-history":[{"count":6,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/2995\/revisions"}],"predecessor-version":[{"id":3007,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/2995\/revisions\/3007"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/media\/3004"}],"wp:attachment":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2995"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2995"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2995"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}