Executando verificação de segurança...
2

Aplicação Desktop Simples em Python com Eel e React: Uma Combinação Poderosa e Fácil de Usar

Recentemente precisei desenvolver uma aplicação desktop para um cliente e queria fazer isso da forma mais direta possível, usando as tecnologias que já conheço, mas sem a necessidade de ter que aprender um novo framework do zero, como o electron. Acabei encontrando a biblioteca eel do Python e fiquei impressionado com a simplicidade e eficácia dela em cumprir o que propõe.

Então, nada melhor do que compartilhar o quão simples é fazer isso!

Basicamente, o que precisaremos fazer é:

1. Instalar o eel

$ pip install eel

2. Criar o script principal, e é tão simples quanto:

# main.py

import eel

# A pasta web é onde ficará nosso projeto React
eel.init("web/src", [".tsx", ".ts", ".jsx", ".js", ".html"])


# Criamos a janela e definimos sua configuração
eel.start({"port": 5173}, host="localhost", port=8080, size=(1000, 600))
#            ^-- a porta que está rodando o react 

Ok, agora que já temos nosso script criado, vamos iniciar nosso projeto react? bora!!

3. Inicie seu projeto React

Com a queda do create-react-app, por que não usar uma bela alternativa como o Vite? Fique à vontade para iniciar da forma que preferir 👍

$ npm create vite@latest

Ótimo. Script criado e projeto react rodando, nossa estrutura de pasta deverá ficar mais ou menos assim:

Texto alternativo da imagem

E é isso, agora é só executar seu script python main.py e, se tudo estiver correto, verá uma nova janela aparecendo na sua tela:


Mas agora você deve estar se perguntando:

Isso não é apenas uma janela simples do chrome?
Sim, é exatamente isso. O eel cria um servidor local e expõe arquivos estáticos (HTML, CSS e JS), é basicamente isso.

Então qual o proposito da utilização do eel?
A facilidade de conexão do seu servidor local e sua interface. Veremos agora como você pode "chamar" uma função JavaScript com o Python e vice-versa 🤯

# main.py

import eel
from time import sleep

eel.init("web/src", [".tsx", ".ts", ".jsx", ".js", ".html"])


@eel.expose
def start_count():
    count = 0

    while True:
        eel.setCount(count)
        count += 1
        sleep(1)


eel.start({"port": 5173}, host="localhost", port=8080, size=(1000, 600))

Criamos nossa função start_count em Python e deixamos ela acessível ao lado do cliente usando o decorator @eel.expose. Veja que, ao chamar essa função, ela executará um loop infinito que sempre estará chamando o método eel.setCount (que iremos criar agora no react).

Agora faremos o mesmo no lado do cliente:

// app.tsx

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

export const eel = window.eel
window.eel.set_host("ws://localhost:8080")

function App() {
  const [count, setCount] = useState(0)

  // expondo o estado para que possa ser acessado pelo python
  window.eel.expose(setCount, "setCount")

  function handleStartCount() {
    window.eel.start_count()
  }

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={handleStartCount}>Start Count</button>
        <div>count is {count}</div>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}

export default App

E pronto, a setCount function estará sendo chamada pelo nosso script python e o estado do react é alterado (claro que sabemos que o estado do react não está literalmente sendo alterado pelo python), então teremos esse resultado:


E não precisa se limitar aí, para uma experiencia de uma janela nativa podemos integrar tudo isso ao pywebview para não termos que executar nossa aplicação desktop em uma janela do chrome.

Carregando publicação patrocinada...
1