Da index.html a index.exe: la magia di PyInstaller e GitHub Actions

Ho realizzato una web app con mappe interattive.
Tutto in HTML, CSS e JavaScript.

Funziona perfettamente… quando viene servita da un webserver.
Il problema è che, per ora, non può essere distribuita pubblicamente.

Le alternative sono due:

  • mettermi a configurare un webserver protetto solo per questa anteprima (no, grazie),
  • oppure far sì che si apra con un doppio clic su index.html.

Purtroppo, però, questo secondo approccio non funziona, vista la complessità del codice JS/HTML e l’uso di fetch per caricare dati.
Il browser blocca tutto: fetch falliti, layer vuoti, errori CORS, silenzio stampa.

Per ragioni di sicurezza, molte funzioni (come fetch) non sono permesse da file locali.

È necessario un web server, anche in locale

La soluzione tecnica è semplice:

cd docs
python -m http.server 8085

Funziona, ma lanciare un comando da terminale non è immediato per chi non ha un minimo di esperienza
Serve qualcosa di più accessibile.

Entra in scena Python

Creo qui uno script start_server.py che:

  1. apre un piccolo server HTTP locale (su porta 8085),
  2. avvia il browser sulla pagina giusta.
import http.server
import socketserver
import webbrowser
import os
PORT = 8085
DIRECTORY = "docs"
os.chdir(DIRECTORY)
Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print(f"Serving at http://localhost:{PORT}")
webbrowser.open(f"http://localhost:{PORT}")
httpd.serve_forever()

Questo funziona per chi ha Python installato. Ma non tutti ce l’hanno. E soprattutto, molti usano Windows.

E se fosse solo un eseguibile?

Sì, certo. Uso Linux, però.
E qui comincia l’avventura.
Potrei installare una macchina virtuale, oppure Wine… o… ma perché complicarsi la vita?

La magia: GitHub Actions + PyInstaller

Con PyInstaller posso creare un eseguibile dal mio script Python, ma solo per il sistema operativo su cui lo eseguo.
Non ho MacOSX e non ho Windows ma con GitHub Actions posso tranquillamente automatizzare l’operazione in ciascuno di questi ambienti.

E la cosa bella è che, ogni volta che effettuo una push (git push), GitHub Actions mi genera automaticamente i tre eseguibili.

Questo il workflow creato

name: Build executables
on:
push:
branches: [ main ]
jobs:
build:
runs-on: $
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
    steps:
- uses: actions/checkout@v4
    - name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
    - name: Install pyinstaller
run: pip install pyinstaller
    - name: Build executable
run: pyinstaller --onefile --name index start_server.py
    - name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: $-index
path: dist/index*

Cosa viene creato?

Alla fine della build, trovo tre pacchetti:

  • index.exe per Windows
  • un binario per Linux (indexcon permessi di esecuzione)
  • una .app per macOS

Basta scaricarli, eseguirli, e l’app parte da sola: il server si avvia, si apre il browser e tutto funziona.

L’app? Tutta inclusa

Nello stesso repository includo anche la cartella docs/ con HTML, JS, immagini e dati.
Così l’eseguibile non serve solo lo script, ma tutta l'applicazione web.

Conclusione

Con un piccolo script Python, un tool come PyInstaller e l’automazione delle GitHub Actions ho:

  • risolto i problemi legati al caricamento locale di web app,
  • creato un pacchetto eseguibile per chi non ha competenze tecniche,
  • automatizzato tutto il processo in pochi minuti.

Il risultato è un’app accessibile con un doppio clic, da qualunque sistema operativo.

Doppio clic, browser che si apre, mappa servita: missione compiuta.