Como criar um app Electron usando Vite
Rafael Beraldo
Posted on July 6, 2022
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
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
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
└── ...
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()
}
})
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 ."
},
...
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
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()
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"
},
...
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
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
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()]
})
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"
},
...
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
Posted on July 6, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.