Så var det dags att hitta ett sätt att göra om appen till en riktig app, en som man klickar igång och använder som ett program. Fördelen är att det är lättare att dela med sig av den så att andra kan prova.

Välja ramverk

Jag började med att utvärdera fyra olika desktop-ramverk för PastPaths. Så här gick mitt resonemang:

Electron vs Tauri

Först hade jag två alternativ, Electron och Tauri.

Electron packar en hel Chromium-webbläsare + Node.js med din app. Din Vue/Quasar-frontend körs i den inbäddade webbläsaren, och du kan starta Flask som en bakgrundsprocess från Node.js.

Tauri använder istället operativsystemets inbyggda webbvy (WebView2 på Windows, WebKit på Mac/Linux). Backend skrivs i Rust. Appen blir mycket mindre och snabbare.

En nackdel med Electron är att den genererar stora filer eftersom den packar en hel Chromium-webbläsare så jag fastnade för Tauri, annars finns stora för- och nackdelar med båda. Som vanligt när jag nästan bestämt mig så kom jag på att jag kanske borde undersöka lite fler alternativ.

pywebview: pywebview är ett Python-bibliotek som öppnar ett fönster med systemets webbvy och kör Flask-appen direkt i samma Python-process.

Wails: Wails fungerar precis som Tauri (systemets webbvy, liten storlek) men backend skrivs i Go. Go är enklare att lära sig än Rust. Samma sidecar-approach för Flask, men Go-toolchainen är smidigare. Dock — om du ändå kör Flask som sidecar ger Wails inget stort försprång över Tauri.

Neutralinojs: Ännu lättare än Tauri (~2–5 MB). Använder systemets webbvy och en minimal backend i C++. Kan starta Flask som extern process. Men ekosystemet är litet och dokumentationen tunn.

Jag landade till slut i pywebview som verkade enklast att komma igång och med möjlighet att migrera till Tauri senare.

Nyckelinsikt: Valet handlade inte om "bäst" utan om "bäst just nu". pywebview ger ganska snabbt en fungerande desktop-app Tauri hade krävt Rust-toolchain och flera timmars setup. Med den kunskap jag samlat på mig vet jag att saker och ting aldrig är så enkla som de verkar och jag vill verkligen komma igång med släktforskningen igen.

pywebview + Flask — ihopsättningen

Först skapade jag launcher.py (~70 rader) som startar Flask i en bakgrundstråd och öppnar ett pywebview-fönster. Tre problem dök upp och löstes:

  • Två servrar på samma port: Frontend och backend körde på olika portar — löste med en catch-all route i Flask som servar den byggda SPA:n
  • Filer sparades på fel plats: os.chdir(BACKEND_DIR) behövdes så att relativa sökvägar i Flask pekar rätt
  • API-routes krock med catch-all: La till API_PREFIXES-guard som skyddar backend-routes från att fångas av frontend-servern

Att få igång appen gick på en timme ungefär men sedan var det ju det där att det är sällan som saker bara flyter på. Jag berättar mer nästa gång.