Arkanus
Menu
FALE CONOSCO
Electron

Electron: Guia Completo Para Criar Apps Desktop com Web Technologies

Descubra como Electron permite construir aplicativos desktop nativos para Windows, Mac e Linux usando HTML, CSS e JavaScript - a mesma stack que você já domina.

Equipe Arkanus

Equipe Arkanus

27/10/2025

Electron: Guia Completo Para Criar Apps Desktop com Web Technologies

Electron: Guia Completo Para Criar Apps Desktop com Web Technologies

Visual Studio Code, Slack, Discord, Figma, Notion - o que todos esses aplicativos têm em comum? Todos são construídos com Electron, o framework que permite criar aplicações desktop cross-platform usando tecnologias web que você já conhece.

Electron Desktop Applications

O que é Electron?

Electron é um framework open-source criado pelo GitHub que permite construir aplicações desktop nativas usando HTML, CSS e JavaScript. Combina Chromium (engine de renderização do Chrome) com Node.js, dando acesso tanto a APIs web quanto a recursos nativos do sistema operacional.

Como Funciona?

┌─────────────────────────────────────┐
│     Sua Aplicação (HTML/CSS/JS)    │
├─────────────────────────────────────┤
│  Chromium (Rendering) + Node.js     │
├─────────────────────────────────────┤
│        Electron Framework           │
├─────────────────────────────────────┤
│   Windows / macOS / Linux           │
└─────────────────────────────────────┘

Chromium: Renderiza sua interface (como um navegador) Node.js: Acessa filesystem, processos, hardware Electron APIs: Bridge entre web e sistema nativo

Por que Electron?

1. Reutilize Código Web

Se você tem uma aplicação web, pode transformá-la em desktop app:

// main.js - Ponto de entrada Electron
const { app, BrowserWindow } = require('electron');

function createWindow() {
  const win = new BrowserWindow({
    width: 1200,
    height: 800,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false
    }
  });

  // Carregar app web local
  win.loadFile('index.html');
  
  // Ou carregar de URL
  // win.loadURL('https://meuapp.com');
}

app.whenReady().then(createWindow);

2. Um Código, Três Plataformas

Escreva uma vez, publique em:

  • Windows (.exe)
  • macOS (.dmg, .app)
  • Linux (.deb, .rpm, AppImage)
# Build para todas plataformas
npm run build:win
npm run build:mac
npm run build:linux

3. Acesso Total ao Sistema

Electron combina poder do navegador com Node.js:

// APIs Web (Chromium)
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');

// APIs Node.js (filesystem, etc)
const fs = require('fs');
const data = fs.readFileSync('/path/file.txt', 'utf8');

// APIs Electron (nativas)
const { dialog, shell } = require('electron');

// Abrir diálogo de arquivo
const files = await dialog.showOpenDialog({
  properties: ['openFile', 'multiSelections']
});

// Abrir arquivo externo
shell.openPath('/path/to/file');

4. Developer Experience Superior

Use ferramentas modernas:

// React
import React from 'react';
import ReactDOM from 'react-dom';

function App() {
  return <h1>Meu App Electron + React</h1>;
}

ReactDOM.render(<App />, document.getElementById('root'));

// Hot reload com Vite
// TypeScript support
// CSS frameworks (Tailwind, etc)
// State management (Redux, Zustand)

Arquitetura Electron

Main Process vs Renderer Process

Main Process (Node.js puro):

  • Controla ciclo de vida do app
  • Cria janelas (BrowserWindow)
  • Acessa APIs nativas
  • Um único main process

Renderer Process (Chromium):

  • Renderiza UI (HTML/CSS/JS)
  • Cada janela = um renderer process
  • Acesso limitado ao sistema (por segurança)
// main.js (Main Process)
const { app, BrowserWindow, ipcMain } = require('electron');

let mainWindow;

app.whenReady().then(() => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false  // Segurança
    }
  });

  mainWindow.loadFile('index.html');
});

// IPC: comunicação Main ↔ Renderer
ipcMain.handle('read-file', async (event, filepath) => {
  return fs.readFileSync(filepath, 'utf8');
});
// renderer.js (Renderer Process)
// Não pode acessar Node.js diretamente por segurança

// Usa IPC para comunicar com Main Process
const conteudo = await window.electronAPI.readFile('/path/file.txt');
console.log(conteudo);
// preload.js (Bridge seguro)
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  readFile: (filepath) => ipcRenderer.invoke('read-file', filepath)
});

Recursos Nativos

File System

const fs = require('fs');
const path = require('path');

// Ler arquivo
const data = fs.readFileSync('/path/file.json', 'utf8');
const json = JSON.parse(data);

// Escrever arquivo
fs.writeFileSync('/path/output.txt', 'Conteúdo', 'utf8');

// Assistir mudanças
fs.watch('/path/directory', (eventType, filename) => {
  console.log(`${filename} changed: ${eventType}`);
});

Notifications

const { Notification } = require('electron');

const notificacao = new Notification({
  title: 'Título',
  body: 'Mensagem da notificação',
  icon: '/path/icon.png'
});

notificacao.show();

notificacao.on('click', () => {
  console.log('Notificação clicada');
});

System Tray

const { Tray, Menu } = require('electron');

const tray = new Tray('/path/icon.png');

const contextMenu = Menu.buildFromTemplate([
  { label: 'Abrir', click: () => mainWindow.show() },
  { label: 'Configurações', click: openSettings },
  { type: 'separator' },
  { label: 'Sair', click: () => app.quit() }
]);

tray.setContextMenu(contextMenu);
tray.setToolTip('Meu App');

Global Shortcuts

const { globalShortcut } = require('electron');

app.whenReady().then(() => {
  // Ctrl+Shift+X
  globalShortcut.register('CommandOrControl+Shift+X', () => {
    console.log('Atalho ativado!');
    mainWindow.show();
  });
});

Clipboard

const { clipboard } = require('electron');

// Copiar texto
clipboard.writeText('Texto copiado');

// Ler texto
const text = clipboard.readText();

// Copiar imagem
const image = nativeImage.createFromPath('/path/image.png');
clipboard.writeImage(image);

Dialog

const { dialog } = require('electron');

// Abrir arquivo
const result = await dialog.showOpenDialog({
  title: 'Selecione arquivo',
  filters: [
    { name: 'Imagens', extensions: ['jpg', 'png', 'gif'] },
    { name: 'Todos arquivos', extensions: ['*'] }
  ],
  properties: ['openFile', 'multiSelections']
});

console.log(result.filePaths);

// Salvar arquivo
const savePath = await dialog.showSaveDialog({
  title: 'Salvar como',
  defaultPath: 'documento.txt',
  filters: [
    { name: 'Text', extensions: ['txt'] }
  ]
});

// Message box
const response = await dialog.showMessageBox({
  type: 'question',
  buttons: ['Cancelar', 'Confirmar'],
  title: 'Confirmação',
  message: 'Tem certeza?'
});

if (response.response === 1) {
  // Confirmar clicado
}

Menu e Menu Bar

const { Menu } = require('electron');

const template = [
  {
    label: 'Arquivo',
    submenu: [
      { 
        label: 'Novo',
        accelerator: 'CmdOrCtrl+N',
        click: () => createNewDocument()
      },
      {
        label: 'Abrir',
        accelerator: 'CmdOrCtrl+O',
        click: () => openFile()
      },
      { type: 'separator' },
      {
        label: 'Sair',
        accelerator: 'CmdOrCtrl+Q',
        click: () => app.quit()
      }
    ]
  },
  {
    label: 'Editar',
    submenu: [
      { role: 'undo', label: 'Desfazer' },
      { role: 'redo', label: 'Refazer' },
      { type: 'separator' },
      { role: 'cut', label: 'Cortar' },
      { role: 'copy', label: 'Copiar' },
      { role: 'paste', label: 'Colar' }
    ]
  },
  {
    label: 'Ajuda',
    submenu: [
      {
        label: 'Documentação',
        click: async () => {
          const { shell } = require('electron');
          await shell.openExternal('https://docs.meuapp.com');
        }
      }
    ]
  }
];

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);

Auto-Updater

Atualizações automáticas:

const { autoUpdater } = require('electron-updater');

autoUpdater.checkForUpdatesAndNotify();

autoUpdater.on('update-available', () => {
  dialog.showMessageBox({
    type: 'info',
    title: 'Atualização disponível',
    message: 'Uma nova versão está disponível. Baixando...'
  });
});

autoUpdater.on('update-downloaded', () => {
  dialog.showMessageBox({
    type: 'info',
    title: 'Atualização pronta',
    message: 'Reinicie para aplicar a atualização.',
    buttons: ['Reiniciar', 'Mais tarde']
  }).then((result) => {
    if (result.response === 0) {
      autoUpdater.quitAndInstall();
    }
  });
});

Frameworks e Stacks Populares

Electron + React

npx create-react-app meu-app
cd meu-app
npm install --save-dev electron electron-builder concurrently wait-on

# package.json
{
  "main": "public/electron.js",
  "scripts": {
    "electron:dev": "concurrently \"BROWSER=none npm start\" \"wait-on http://localhost:3000 && electron .\""
  }
}

Electron + Vue

vue create meu-app
cd meu-app
vue add electron-builder
npm run electron:serve

Electron + Next.js

npm install --save-dev electron electron-builder electron-is-dev
# Use next export para build estático

Electron Forge

CLI oficial:

npx create-electron-app meu-app
cd meu-app
npm start

# Build
npm run make

Segurança

Electron apps podem ser vulneráveis se não seguir best practices:

1. Context Isolation

webPreferences: {
  contextIsolation: true,  // ✅ Sempre true
  nodeIntegration: false,  // ✅ Sempre false
  preload: path.join(__dirname, 'preload.js')
}

2. Sanitize Input

// ❌ Nunca
const data = JSON.parse(untrustedInput);
eval(untrustedCode);

// ✅ Sempre valide
const data = safeParse(input);

3. Content Security Policy

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self'">

4. Disable Node Integration

// Renderer não deve ter Node.js direto
nodeIntegration: false

5. Use Preload Scripts

// preload.js - Bridge seguro
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('api', {
  // Exponha apenas o necessário
  saveFile: (data) => ipcRenderer.invoke('save-file', data),
  loadFile: () => ipcRenderer.invoke('load-file')
});

Performance

1. Lazy Loading

// Carregue janelas sob demanda
let settingsWindow = null;

function openSettings() {
  if (settingsWindow) {
    settingsWindow.focus();
    return;
  }
  
  settingsWindow = new BrowserWindow({ width: 600, height: 400 });
  settingsWindow.loadFile('settings.html');
  
  settingsWindow.on('closed', () => {
    settingsWindow = null;
  });
}

2. Background Throttling

win.webContents.setBackgroundThrottling(false);
// Disable para apps que rodam em background

3. OffscreenWindow

Renderização em background:

const { BrowserWindow } = require('electron');

const win = new BrowserWindow({
  width: 800,
  height: 600,
  show: false,
  webPreferences: {
    offscreen: true
  }
});

win.webContents.on('paint', (event, dirty, image) => {
  // Processar frame
});

Build e Distribuição

Electron Builder

// package.json
{
  "build": {
    "appId": "com.arkanus.meuapp",
    "productName": "Meu App",
    "directories": {
      "buildResources": "assets"
    },
    "files": [
      "dist/**/*",
      "node_modules/**/*",
      "package.json"
    ],
    "win": {
      "target": ["nsis", "portable"],
      "icon": "assets/icon.ico"
    },
    "mac": {
      "target": ["dmg", "zip"],
      "icon": "assets/icon.icns",
      "category": "public.app-category.productivity"
    },
    "linux": {
      "target": ["AppImage", "deb", "rpm"],
      "icon": "assets/icon.png",
      "category": "Utility"
    }
  },
  "scripts": {
    "build": "electron-builder",
    "build:win": "electron-builder --win",
    "build:mac": "electron-builder --mac",
    "build:linux": "electron-builder --linux"
  }
}

Code Signing

macOS:

export CSC_LINK=/path/certificate.p12
export CSC_KEY_PASSWORD=password
npm run build:mac

Windows:

export CSC_LINK=/path/certificate.pfx
export CSC_KEY_PASSWORD=password
npm run build:win

Casos de Uso

Editores de Código: VS Code, Atom Comunicação: Slack, Discord, Microsoft Teams Design: Figma (desktop), InVision Produtividade: Notion, Obsidian, Todoist Desenvolvimento: Postman, GitKraken, MongoDB Compass Streaming: OBS Studio, Streamlabs

Electron vs Alternativas

Electron:

  • Ecossistema maduro
  • Comunidade massiva
  • Bundle size maior (~70MB+)

Tauri:

  • Rust-based
  • Bundle minúsculo (~5MB)
  • Performance melhor
  • Menos maduro

NW.js:

  • Similar ao Electron
  • Menos popular

PWA:

  • Web-only
  • Limitações de acesso nativo

Conclusão

Electron democratizou desenvolvimento desktop. Desenvolvedores web podem criar aplicações desktop nativas profissionais sem aprender tecnologias nativas específicas de cada plataforma.

Vantagens: ✅ Web technologies: HTML/CSS/JS que você conhece ✅ Cross-platform: Windows, Mac, Linux com um código ✅ Acesso nativo: Filesystem, notificações, hardware ✅ Ecosystem: React, Vue, frameworks modernos ✅ Rápido desenvolvimento: Reutilize código web

Desvantagens: ❌ Bundle size: Apps grandes (70MB+ base) ❌ Memória: Chromium consome RAM ❌ Startup: Mais lento que nativo puro

Na Arkanus, usamos Electron para:

  • Ferramentas internas desktop
  • Apps corporativos cross-platform
  • Protótipos rápidos desktop
  • Extensões de apps web existentes

Se você precisa transformar sua aplicação web em desktop, ou criar uma nova ferramenta desktop cross-platform, Electron é uma ótima escolha - e podemos ajudar.


Quer criar um aplicativo desktop com Electron? Nossa equipe domina web technologies e Electron. Fale conosco.

Equipe Arkanus

Equipe Arkanus

Equipe Arkanus escreve sobre tecnologia, transformação digital e engenharia de software na Arkanus.

Compartilhe este artigo

Artigos Relacionados