Como criar um app Electron usando Vite

rafaelberaldo

Rafael Beraldo

Posted on July 6, 2022

Como criar um app Electron usando Vite

This article is also in english.

Então você quer disponibilizar seu novo aplicativo em Vite usando Electron, mas não quer usar o código pronto dos outros. Vamos entender como funciona e fazer o nosso próprio.

Criar um app Vite

Nós vamos utilizar a estrutura de arquivos do Vite como base do nosso projeto. Inicie com o comando:

$ npm create vite@latest
Enter fullscreen mode Exit fullscreen mode

Depois siga as instruções no terminal. Neste exemplo eu utilizei o preset react-ts. Mas também funciona com Vuejs e provavelmente todos outros.

Adicione o Electron

Agora adicionamos o Electron ao nosso projeto:

$ npm i -D electron@latest
Enter fullscreen mode Exit fullscreen mode

Depois criamos um diretório electron na raíz, e dois arquivos main.js e preload.js. Nossa estrutura de arquivos ficou assim:

project-root/
├── electron/
│   ├── main.js 
│   └── preload.js
├── src/
│   └── ...
├── index.html
├── package.json
├── vite.config.ts
└── ...
Enter fullscreen mode Exit fullscreen mode

Arquivo de entrada do Electron

Electron precisa de um arquivo de entrada para funcionar, vamos editar o electron/main.js:

const { app, BrowserWindow, shell } = require('electron')
const { join } = require('path')

if (!app.requestSingleInstanceLock()) {
  app.quit()
  process.exit(0)
}

let win = null

async function createWindow () {
  win = new BrowserWindow({
    title: 'Main window',
    width: 1024,
    height: 768,
    webPreferences: {
      preload: join(__dirname, '../electron/preload.js'),
      nodeIntegration: true
    }
  })

  if (app.isPackaged) {
    // win.removeMenu()
    win.loadFile(join(__dirname, '../dist/index.html'))
  } else {
    // Vite's dev server
    win.loadURL('http://localhost:5173')
    win.webContents.openDevTools()
  }

app.whenReady().then(createWindow)

app.on('window-all-closed', () => {
  win = null
  if (process.platform !== 'darwin') app.quit()
})

app.on('second-instance', () => {
  if (win) {
    // Focus on the main window if the user tried to open another
    if (win.isMinimized()) win.restore()
    win.focus()
  }
})

app.on('activate', () => {
  const allWindows = BrowserWindow.getAllWindows()
  if (allWindows.length) {
    allWindows[0].focus()
  } else {
    createWindow()
  }
})
Enter fullscreen mode Exit fullscreen mode

O arquivo preload.js vai ficar em branco para esse tutorial. Mas você provavelmente vai utilizar num aplicativo real.

Adicione-o ao package.json:

  ...
+ "main": "electron/main.js",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
+   "electron:dev": "electron ."
  },
  ...
Enter fullscreen mode Exit fullscreen mode

Você já pode testar, execute o dev server do Vite num terminal, e do Electron em outro:

# Primeiro terminal
$ npm run dev

# Segundo terminal
$ npm run electron:dev
Enter fullscreen mode Exit fullscreen mode

Repare que estão completamente desacoplados, o HMR funciona normalmente já que só estamos abrindo o dev server do Vite no Electron.

Mas eu quero executar de um único terminal/comando!

Para isso podemos criar um script customizado. Crie um novo arquivo scripts/dev.mjs com:

import { spawn } from 'child_process'
import { createServer } from 'vite'
import electron from 'electron'

const server = await createServer({ configFile: 'vite.config.ts' })

spawn(electron, ['.'], { stdio: 'inherit' }).once('exit', process.exit)

await server.listen()
Enter fullscreen mode Exit fullscreen mode

E atualize o script no package.json:

...
"scripts": {
  "dev": "vite",
  "build": "tsc && vite build",
  "preview": "vite preview",
- "electron:dev": "electron ."
+ "electron:dev": "node scripts/dev.mjs"
},
...
Enter fullscreen mode Exit fullscreen mode

Agora você pode abrir ambos dev server num único comando npm run electron:dev.

Note que nesse exemplo não teremos Live Reload nem TypeScript no electron/main.js. Para isso funcionar você pode implementar algo parecido com isso. Na minha opinião não é necessário na maioria dos casos.

Gerando o executável

Nosso dev server está funcionando bem. Agora temos que gerar o executável do app.

Vamos usar o electron-builder. Adicione ao projeto:

$ npm i -D electron-builder
Enter fullscreen mode Exit fullscreen mode

E precisamos de uma arquivo de configuração, crie o electron-builder.yaml na raíz:

# https://www.electron.build/configuration/configuration

appId: your.app.id
asar: true
directories:
  output: release/${version}

files:
- dist
- electron

mac:
  artifactName: "${productName}_${version}.${ext}"
  target:
  - dmg
win:
  target:
  - target: nsis
    arch:
    - x64
  artifactName: "${productName}_${version}.${ext}"
nsis:
  oneClick: false
  perMachine: false
  allowToChangeInstallationDirectory: true
  deleteAppDataOnUninstall: false
Enter fullscreen mode Exit fullscreen mode

Adicione a propriedade base ao arquivo de configuração do Vite vite.config.ts:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  base: './',
  plugins: [react()]
})
Enter fullscreen mode Exit fullscreen mode

Isso adiciona o prefixo ./ em todos assets, necessário para funcionar com o protocolo file:// do Electron.

Agora adicione o script ao package.json:

...
"scripts": {
  "dev": "vite",
  "build": "tsc && vite build",
  "preview": "vite preview",
  "electron:dev": "node scripts/dev.mjs",
+ "electron:build": "npm run build && electron-builder"
},
...
Enter fullscreen mode Exit fullscreen mode

Como você pode ver, iremos primeiramente executar a build do Vite, e depois do Electron.

A build do Vite estará localizada no diretório dist, a build do Electron estará localizada no diretório release. Adicione ambos ao .gitignore.

Agora você pode buildar o app com o comando npm run electron:build.

Eeee é isso! Você agora tem seu app Electron usando Vite!

Código completo do tutorial: https://github.com/rafaberaldo/vite-electron

Referências

💖 💪 🙅 🚩
rafaelberaldo
Rafael Beraldo

Posted on July 6, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related