Vue-Python

FastAPI geht Full Stack

Die Geschichte, wie Vue die Schlange sah und sich verliebte.

FastAPI ist eines dieser Stücke von Software, die mich misstrauisch machen, weil die Python-Backend-Geschichte ist Zu Angenehm. Typ-Hinweise in Flask/Express-Stil-Handlern werden zu Parsing und Validierung. Async mit automatischen Neuladungen funktioniert ohne das Aufrufen einer eldritch Framework-Konfigurationsanleitung. Fügen Sie seine OpenAPI-Schemata und automatische Neuladungen hinzu, und Sie können von git init Zu einer respektablen API, bevor die Kaffeemaschine ihre Boot-Sequenz beendet hat.

Dann brauchst du ein Frontend.

Historisch gesehen ist dies der Ort, an dem die neonbeleuchtete Schnellstraße abrupt an einer Betonmauer endete.

FastAPI Es ist sehr gut bei APIs, aber es kann Ihr Frontend nicht wirklich an der Site-Root bedienen, es sei denn, Sie wollten das Alles Ihre Anfragen werden weitergeleitet an StaticFilesUnd SPA-Unterstützung ist unerhört. Sie könnten Dateien bereitstellen, Vorlagen rendern oder beliebige Mechanismen anhängen, aber die letzte Meile zwischen einem modernen JavaScript-Frontend und der Python-Anwendung wurde weitgehend als Übung für den Leser hinterlassen.

Und dieser Leser war zunehmend ich.

In der Zwischenzeit, im Frontend-Bereich

Ich verwende Vue für diesen Job. Vue befindet sich ungefähr im gleichen Bereich wie React und Svelte: komponentenbasierte Schnittstellen, reaktiver Zustand, clientseitiges Routing und die übliche moderne Maschinerie, um einen Stapel von Quelldateien in etwas umzuwandeln, das ein Browser ausführen kann.

Das fastapi-vue Das Paket kann jedoch auch mit anderen verwendet werden, also beschreibe ich die Konkurrenten kurz.

Reagieren

React ist der allmächtige Marktführer. Es hat ein riesiges Ökosystem, eine Antwort auf alles und normalerweise drei weitere Antworten, die mit der ersten in Widerspruch stehen.

Sein größter praktischer Vorteil ist einfach die Schwerkraft: Viele Entwickler kennen es, viele Bibliotheken zielen darauf ab, und viele Beispielcodes beginnen damit npm install reactEs ist weitaus beliebter als Vue, was die relativ schwache Integration zwischen React und FastAPI an sich ziemlich bezeichnend macht.

Selbst die offizielle FastAPI-Full-Stack-Lösung - die erst vor einigen Wochen veröffentlicht wurde - ist im Grunde ein Vorlagen-Repository: ein vorgewählter React-Stack, von dem aus Sie starten, anstatt Werkzeuge, die in eine bestehende Python-Anwendung integriert werden können und ein Frontend darin einbinden können.

Schlank

Svelte verfolgt einen eher compilerlastigen Ansatz. Anstatt so viel Framework-Hardware in den Browser zu schicken, transformiert es Komponenten zur Build-Zeit. Das Ergebnis kann in der Produktion auch ohne Node ausgeführt werden.

Es erfordert ein wenig Geschicklichkeit für eine korrekte Reaktivität, wobei $ in seiner benutzerdefinierten Sprache erforderlich ist, um anzuzeigen, was ein Update benötigt. Auf der anderen Seite ermöglicht diese benutzerdefinierte Sprache einen kürzeren Code als bei ihren Konkurrenten.

Vue

Vue befindet sich an einem Ort, den ich ziemlich mag: genug Struktur, um substanzielle Anwendungen zu erstellen, aber ohne das HTML unter mehreren geologischen Schichten von JavaScript zu verschwinden. Die Reaktivität mit seinem Pinia-Store funktioniert einfach und bleibt im Hintergrund. Und wenn Sie das absolut letzte bisschen Leistung benötigen, integriert es sich gut in nicht-reaktive Strukturen. Keine komplizierte Umhüllung oder useState Und solch ein Boilerplate ist erforderlich.

Und es läuft schnell, was bei den meisten React-Apps nicht der Fall ist.

Es ist offiziell create-vue Das Tool gibt mir hier auch etwas besonders Nützliches: Ich muss nicht erfinden Mein Eine Vorstellung davon, wie ein Vue-Projekt aussehen sollte. Es kann interaktiv fragen, ob die Anwendung TypeScript, Vue Router, Pinia, Vitest, Playwright/Cypress, ESLint, Prettier und den Rest der üblichen Ausrüstung verwenden sollte.

Das wird später wichtig.

Vue-Svelte-React
Das Lösen eines minimalen Webformulars, das häufig in Anwendungen erscheint: ein Dropdown, um einen Datensatz zum Bearbeiten auszuwählen, mit Eingaben für seine Felder. Svelte hat den kürzesten Code, aber Vue ist eine einfache Browser-index.html und hat wirklich nur die gleiche Länge. Und dann kommt React mit zu viel Arbeit, um in einen Screenshot zu passen. Alle Aufgaben sind in React und dieses Bild zeigt warum.

Wie setzen wir dieses Ding eigentlich ein?

Sobald ich FastAPI auf der einen Seite und Vue, React oder Svelte auf der anderen Seite habe, gibt es ein paar grundlegend unterschiedliche Möglichkeiten, wie ich das resultierende Gebilde auf einen Server stellen kann.

Option 1: sich Node ergeben

Die offensichtliche Antwort in der JavaScript-Welt ist, auch einen JavaScript-Server in Produktion zu setzen.

Das macht sehr viel Sinn, wenn ich tatsächlich ein Node-Backend möchte. Es gibt einen echten Vorteil darin, eine Sprache und eng verwandte Werkzeuge auf beiden Seiten der Verbindung zu haben. Wenn mein Team überall TypeScript haben möchte, ist das eine vollkommen kohärente Architektur.

Das tue ich nicht.

Ich habe FastAPI gewählt, weil ich das Backend in Python schreiben möchte. Eine weitere Laufzeitumgebung nebenher zu installieren, nur um Frontend-Assets zu liefern, fühlt sich an, als würde man einen zweiten Koch einstellen, um Teller von der Küche ins Esszimmer zu bringen.

Bild
Will ich Gigabytes an node_modules und das auf meinem Produktionsserver? Nein.

Es gibt auch die kleine Angelegenheit des JavaScript-Abhängigkeitsuniversums. Es ist zu schwer, bietet wenig Kompatibilität und ist oft defekt. Während nvm Man kann zwar leicht die richtige Node-Version installieren, aber das benötigt immer noch eine enorme Menge an Speicherplatz, den gehostete Server oft nicht haben.

Node ist nützlich auf meiner Entwicklungsmaschine. Vite ist ausgezeichnet. create-vue Ist ausgezeichnet. Das Build-Ökosystem erledigt seine Aufgabe extrem gut.

Das bedeutet nicht, dass ich irgendetwas davon auf der Produktionsmaschine haben möchte.

Option 2: Rendere alles auf dem Server

Am anderen Ende des Spektrums kann ich den SPA vollständig überspringen und HTML in Python generieren.

Das verdient mehr Respekt, als es manchmal bekommt. Nicht jede Anwendung benötigt eine clientseitige Anwendungs-Runtime, einen Router und mehrere Megabyte an unterstützender Zivilisation.

Tools wie htmx können server-gerendertes HTML überraschend weit bringen, indem sie HTTP-Anfragen, Swaps, Übergänge, WebSockets und vom Server gesendete Ereignisse direkt über HTML-Attribute hinzufügen. Kombinieren Sie dies mit html5tagger, um diese Dokumente und HTML-Fragmente auf dem Server zu erstellen, und Sie werden eine Website haben, die überall läuft und von sozialen Medien, Suchmaschinen und Agenten gleichermaßen gelesen werden kann.

Für Websites, die von Dokumenten, Formularen und relativ einfachen Interaktionen dominiert werden, mag ich diese Architektur. Der Browser fordert etwas an, Python erzeugt HTML, und niemand braucht eine Build-Pipeline, die in der Lage ist, eine Mars-Sonde zu starten.

Vasanko.com basiert auf dieser Methode, wobei Vue nur für die Admin-Oberfläche verwendet wird, wo eine stärkere Interaktivität erforderlich ist. Dieses CMS läuft auf FastAPI-Vue-Einstellungen, rendert aber alle Seiten serverseitig in Python.

Option 3: Zwei Server betreiben

Der übliche Kompromiss ist daher:

  • FastAPI führt die API aus.
  • Vite oder ein anderer JavaScript-Server betreibt das Frontend
  • Ein Reverse-Proxy platziert beide unter einem Hostnamen.
  • Die Produktion hat jetzt zwei Anwendungen, zwei Abhängigkeitsstapel, zwei Prozesse und eine weitere Konfigurationsdatei, die alles zusammenhält.

Das funktioniert, aber es ist nicht schön.

Der Browser kümmert sich nicht darum, ob app.js Was von Python, Node, Caddy, nginx oder einem ausreichend entschlossenen Toaster emittiert wurde. Sobald das Frontend erstellt wurde, ist das Ergebnis statischer HTML, CSS, JavaScript, Schriftarten und Bilder.

Also warum sollte man die Fabrik weiterlaufen lassen, nachdem das Produkt bereits das Fließband verlassen hat?

Bauen Sie mit JavaScript, führen Sie mit Python aus

Das wurde zur zentralen Idee hinter fastapi-vue-setup.

Ich möchte JavaScript-Tools, die tatsächlich nützlich sind:

  • create-vue Um das Frontend zu erstellen
  • Vite für den Entwicklungsserver
  • Sofortige heiße Neuladungen bei Änderungen
  • Der normale Vue-Build auf Node, Bun oder Deno

Und dann will ich, dass es verschwindet.

Das Produktionsartefakt sollte ein Python-Paket sein, das ein bereits erstelltes Frontend enthält. Die Installation dieses Pakets sollte nicht Node, npm, Vite, Vue-Quellcode oder die gravitative Anomalie erfordern, die traditionell unter node_modules.

Das ist genau, wie fastapi-vue-setup Bauen Projekte heute: uv build Führt den Frontend-Build aus und beinhaltet die resultierenden Assets innerhalb des Python-Pakets. Die generierte Hatch-Konfiguration behandelt frontend-build als ein Artefakt und hakt den Build der Quelldistribution ein, während er den Paketinhalt auf das Python-Paket selbst beschränkt.

Die Unterscheidung ist besonders für einen SDIST wichtig. Ich möchte nicht, dass eine Quelldistribution bedeutet “Hier ist etwas Python, hier ist ein kompletter Vue-Entwicklungsbaum, jetzt installiere bitte Node und rekonstruiere die eigentliche Anwendung selbst”. Das Frontend wird bereits kompiliert, bevor die Distribution meinen Computer verlässt.

Das Paket enthält das, was es zum Ausführen benötigt, nicht alles, was ich zum Erstellen davon benötigt habe.

Das lässt den Einsatz wunderbar langweilig erscheinen:

uvx my-app

Keine Node-Installationszeremonie auf dem Zielgerät. Keine npm installKein Frontend-Server. Kein JavaScript-Abhängigkeitsbaum, der drei Monate später aufwacht und darum bittet, gefüttert zu werden.

Das Paket startet FastAPI, und FastAPI bedient die Anwendung.

Das andere hässliche Problem

Das Frontend zu bauen, war nur die Hälfte davon.

StaticFiles ist nicht gerade ein Frontend-Server

FastAPI stellt Starlettes StaticFiles, und für gewöhnliche statische Assets tut es genau das, was es auf der Verpackung verspricht:

app.mount("/static", StaticFiles(directory="static"))

Das Problem beginnt, wenn das Frontend die Website selbst ist.

Eine Vue-Anwendung möchte normalerweise /Es könnte auch wollen /login, /settings, /dashboard/coffee-reactor/7, und alles andere, das dem clientseitigen Router gehört.

Aber das Mounten StaticFiles Bei / Effektiv übergibt das mountete Anwendung die gesamte verbleibende URL-Fläche. FastAPIs eigener Maintainer erklärte das Problem vor Jahren: Mountet es an der Wurzel und die statische Anwendung übernimmt, so funktionieren die normalen Pfadoperationen darunter nicht mehr wie erwartet.

Und wir brauchen:

  • Frontend-Build bei /*
  • FastAPI behandelt immer noch
    • /api/...
    • /openapi.json
    • Jegliche beliebigen anderen Routen

Das ist nicht das gleiche Problem wie das Servieren /static/logo.svg.

FastAPI hat vor kurzem seine eigene Frontend-Unterstützung verbessert, und die aktuelle Dokumentation weist Frontend-Anwendungen nun explizit in Richtung app.frontend() Anstatt von plain StaticFilesAber fastapi-vue Es ist älter als diese Lösung und hat auch eine etwas andere Aufgabe: Es ist die kleine Laufzeit-Hälfte dieses kompletten Paketierungssystems.

Laufzeit von fastapi-vue

Der Begleiter fastapi-vue Das Paket bietet einen benutzerdefinierten Frontend Handler anstelle von Mounting StaticFiles Über die Anwendung.

Im SPA-Modus kann es zurückkehren index.html Für Pfade, die zum clientseitigen Router gehören, anstatt eine physische Datei mit diesem Namen zu benötigen.

Note

Aufgrund der Funktionsweise des FastAPI-Routing verschlingen App-Mounts alles unter diesem Pfad. Die restlichen Routen werden in der Reihenfolge ausprobiert, und die erste gewinnt. Daher müssen wir im SPA-Modus den Catch-All als letztes in dem App-Modul platzieren.

Wenn der SPA-Modus deaktiviert ist, bindet er nur an Pfade von tatsächlichen Dateien, so dass Ihre Routen danach immer noch alles erfassen, was durchfällt.

Es kümmert sich auch um die weniger glamourösen Details, die ich nicht besonders Lust habe, jeden Dienstag neu zu implementieren:

  • ETag und Last-Modified
  • Unveränderbares Caching für erstellte Assets
  • RAM-Caching mit zstd-Komprimierung
  • SPA-Routing-Fallback und /favicon.ico Wenn nötig
  • Serviere nicht versehentlich einen veralteten Build im Entwicklungsmodus

Dies ist die Laufzeitabhängigkeit der Produktion. Sie ist winzig und nur für Python.

Die gesamte Maschinerie zum Bau und zur Entwicklung der Vue-Anwendung bleibt im Quellprojekt.

Eingeben fastapi-vue-setup

Mit diesen Teilen an Ort und Stelle, fastapi-vue-setup Es geht hauptsächlich darum, die repetitive Verkabelung zu entfernen.

Der grundlegende Befehl ist absichtlich nicht sehr aufregend: Weisen Sie ihn auf Ihren App-Ordner hin, oder . Wenn du bereits dort bist.

uvx fastapi-vue-setup my-app

Müssen Sie die Portnummern ändern, die Ihr Prod, Vite und Dev Backend standardmäßig verwenden? Führen Sie es mit aus --ports. Ohne das behält es die Ports, die Sie zuvor konfiguriert hatten. Und Sie können immer --listen Auf deiner CLI oder scripts/devserver.py Um das zur Laufzeit zu ändern.

Aber es gibt zwei ziemlich unterschiedliche Fälle, die sich dahinter verbergen.

Und es bietet Support-Utilitäten für den CLI-Einstiegspunkt, den Ihre App erhält, der dann auch Ihre eigenen Befehlszeilenoptionen übernehmen kann, etwas, das fastapi run Kann nicht bereitstellen.

Erstellung einer neuen Anwendung

Für ein neues Projekt möchte ich nicht fastapi-vue-setup Um eine gefrorene Vue-Vorlage meiner eigenen Erstellung aufzuzwingen. Ich möchte, dass sie ein Python-Projekt erstellt, das mit dem Namen, den ich ihm gegeben habe, und dem Vue-Setup, das ich wähle, konfiguriert ist:

  • JavaScript oder TypeScript
  • Vue Router oder kein Router
  • Pinia oder nicht
  • Tests, Linting und Formatierungsoptionen
  • Die anderen Optionen, die von der aktuellen Version unterstützt werden create-vue

Das Tool baut dann die FastAPI-Integration um die Anwendung herum auf, die der Entwickler tatsächlich ausgewählt hat.

Das ist wichtig, weil eine Vorlage unweigerlich jemandes Vorlieben versteinert. Sechs Monate später könnte seine Vorstellung von einem modernen Full-Stack bereits in einer Museumsausstellung zu sehen sein, und du steckst mit dem fest, was du hast.

Ich hätte lieber die Wahl.

Einrichtung abgeschlossen

Hast du schon eine App?

Hier habe ich vielleicht schon ein echtes Projekt mit Code, den ich lieber nicht verschwinden lassen möchte. Es kann mit dem gleichen Skript oder eigenständig erstellt werden, und das Skript wird es bei Bedarf patchen.

Das Setup-Skript erkennt das Python-Projekt und das Backend-Modul, erkennt oder erstellt das Vue-Frontend und patchet die Teile, die es sicher mit minimalen Änderungen integrieren kann.

Note

Bewegen Sie Ihr bestehendes Vue vollständig unter frontend/ Erstens. Wir platzieren Vue dort, um die Wurzel nicht mit Node-Dingen zu verschmutzen. Wir platzieren es dort, damit das Skript die bestehende App patchen kann, anstatt eine neue zu erstellen.

Müssen Sie auf die neueste Version upgraden? Führen Sie einfach fastapi-vue-setup Wiederholen Sie es und es wird die neuen Funktionen, die es hat, einfügen.

Das ist einer der Hauptunterschiede zwischen diesem und einem Vorlagen-Repository.

Eine Vorlage sagt:
Gabeln Sie dieses Repository, um Ihr Projekt zu starten

Ich brauchte Werkzeuge, die auch sagen können:
In Ordnung, du bist schon bei 30.000 Zeilen. Zeig mir, wo der Patient ist.

Deine App ist bereit zum Ausführen

uv run scripts/devserver.py

vite.config.js

Konfigurieren Sie, welche Pfade an das Backend weitergeleitet werden. Standardmäßig ist dies einfach /apiDiese Konfiguration betrifft nur das Entwicklungs-Setup, in der Produktion landet alles auf FastAPI.

JS_RUNTIME

Umgebung mit Wert bun/deno/node oder Pfad zu einem von ihnen (ansonsten finden wir einen).

Das startet den Vue/Vite-Entwicklungsserver und FastAPI mit Reload-Unterstützung. Die generierte Vite-Integration proxyt Backend-Anfragen an den Python-Entwicklungsserver. Ihr Browser verbindet sich mit Vite.

Also während der Entwicklung bekomme ich immer noch die Dinge, die ich eigentlich am JavaScript-Ökosystem mag.

Hallo Welt, FastAPI verbindet

Wenn die Entwicklung abgeschlossen ist:

uv build  # Installs and (re)builds everything
my-app    # CLI entry point provided (in .venv)

Vue wird kompiliert, das Ergebnis wird in die Python-Distribution integriert, und die Build-Maschine hat ihre Aufgabe erfüllt. Sie können uv publish Ihr Paket, wenn Sie es wünschen, oder einfach von nach Prod kopieren dist/Dann installieren und ausführen mit:

uv tool install my-app-0.1.0.tar.gz
my-app

Alles, was ich vorher installieren musste, war UV Und auf dem Entwicklungssystem Node Selbst. Ich musste nichts anfassen npm Überhaupt nicht, und jetzt kann ich es irgendwo anders installieren oder ausführen, ohne den JavaScript-Workshop mitzunehmen.

Eine Anwendung, endlich

Was ich letztlich wollte, war nicht besonders exotisch.

  • Ich wollte das Backend in Python schreiben.
  • Ich wollte das Frontend in Vue schreiben.
  • Ich wollte Vite, während ich es entwickelte.

Und ich wollte eine Sache schnell einrichten und bereitstellen.

Nicht eine Python-Anwendung plus eine JavaScript-Anwendung. Nicht zwei Container, die durch nginx und gegenseitigem Misstrauen miteinander verbunden sind.

A <1MB Python package that Einfach funktioniert™.

Es enthält das Frontend. FastAPI stellt es von der Site-Root bereit, ohne den Rest der Anwendung zu verschlucken. Vue-Routing funktioniert, wenn ich eine SPA möchte, und einfaches Datei-Routing ermöglicht es meinem Backend, alle Catch-Alls für sich zu behalten, z. B. die Handhabung jeder hübschen URL mit serverseitig gerenderten Inhalten wie auf dieser Site. Das wiederum kann Vue an den Stellen verwenden, wo es nötig ist, zwei Welten in perfekter Harmonie.

Die JavaScript-Toolchain tut das, was eine Toolchain tun soll:

Es baut die Software und geht dann aus dem Weg.

Als nächstes benötigt Ihr Full-Stack eine Datenbank, und Kanta sorgt dafür. Mit dieser Toolchain wird Ihre App in kürzester Zeit laufen.