Vue-Python

FastAPI yendo a Full Stack

La historia de cómo Vue vio la serpiente y se enamoró.

FastAPI es una de esas piezas de software que me hace sospechar porque la historia del backend de Python es Demasiado Agradable. Los tip hints en los controladores de estilo Flask/Express se convierten en análisis y validación. El modo asíncrono con recargas automáticas funciona sin invocar una configuración manual del marco de trabajo de Eldritch. Añade sus esquemas OpenAPI y recargas automáticas y puedes pasar de git init A una API respetable antes de que la máquina de café haya terminado su secuencia de arranque.

Luego necesitas un frontend.

Históricamente, aquí es donde la autopista iluminada con neón terminaba abruptamente en una pared de hormigón.

FastAPI Es muy bueno en APIs, pero en realidad no puede servir a tu frontend en la raíz del sitio, a menos que tú lo desees Todo Tus solicitudes se enrutan a StaticFilesY el soporte de SPA es inaudito. Podrías servir archivos, renderizar plantillas o adjuntar la maquinaria que quisieras, pero la última milla entre una interfaz de JavaScript moderna y la aplicación de Python se dejó en gran parte como un ejercicio para el lector.

Y ese lector era cada vez más yo.

Mientras tanto, en el mundo del frontend

Utilizo Vue para este trabajo. Vue se encuentra aproximadamente en el mismo ámbito que React y Svelte: interfaces basadas en componentes, estado reactivo, enrutamiento del lado del cliente y la maquinaria moderna habitual para convertir una pila de archivos de código fuente en algo que un navegador pueda ejecutar.

El fastapi-vue Sin embargo, el paquete también se puede usar con otros, así que estoy describiendo brevemente a los contendientes.

Reacciona

React es el gorila de 800 libras. Tiene un ecosistema colosal, una respuesta para todo, y por lo general tres respuestas adicionales que discuten con la primera.

Su mayor ventaja práctica es simplemente la gravedad: muchos desarrolladores lo conocen, muchas bibliotecas lo tienen como objetivo, y muchos códigos de ejemplo comienzan con npm install reactEs mucho más popular que Vue, lo que hace que la integración relativamente escasa entre React y FastAPI sea bastante reveladora en sí misma.

Incluso la solución full-stack oficial de FastAPI, lanzada hace solo unas semanas, es fundamentalmente un repositorio de plantillas: una pila de React preseleccionada desde la que comienzas, en lugar de herramientas que puedan integrarse en una aplicación Python existente y conectar un frontend a ella.

Esvelto

Svelte adopta un enfoque más centrado en el compilador. En lugar de enviar bastante maquinaria de framework al navegador, transforma los componentes en tiempo de compilación. El resultado aún puede funcionar sin Node en producción.

Requiere un poco de astucia para una reactividad correcta, que requiere $ en su lenguaje personalizado para indicar lo que necesita una actualización. Por otro lado, este lenguaje personalizado permite un código más corto que el de sus competidores.

Vue

Vue se encuentra en un lugar que me gusta bastante: suficiente estructura para construir aplicaciones sustanciales, pero sin hacer que el HTML desaparezca bajo varias capas geológicas de JavaScript. La reactividad con su tienda Pinia simplemente funciona, y no se interpone en el camino. Y cuando necesitas ese último bit de rendimiento absoluto, se integra bien con estructuras no reactivas. Sin envolturas complicadas o useState Y se requiere tan poco código boilerplate.

Y funciona rápido, lo cual no es el caso con la mayoría de las aplicaciones de React.

Es oficial create-vue La herramienta también me ofrece algo particularmente útil aquí: no tengo que inventar Mi La idea de cómo debería ser un proyecto Vue. Puede preguntar interactivamente si la aplicación debería usar TypeScript, Vue Router, Pinia, Vitest, Playwright/Cypress, ESLint, Prettier y el resto del equipo habitual.

Eso se vuelve importante más tarde.

Vue-Svelte-React
Resolviendo un formulario web mínimo que aparece con frecuencia en las aplicaciones: un menú desplegable para elegir un registro que editar con entradas para sus campos. Svelte tiene el código más corto, pero Vue es un simple índice de navegador .html y realmente de la misma longitud. Y luego viene React con demasiado trabajo para caber en una captura de pantalla. Todos los trabajos están en React y esta imagen muestra por qué.

¿Cómo desplegamos realmente esta cosa?

Una vez que tengo FastAPI por un lado y Vue, React o Svelte por el otro, hay algunas formas fundamentalmente diferentes en las que puedo poner la criatura resultante en un servidor.

Opción 1: rendirse a Node

La respuesta obvia en el mundo de JavaScript es poner un servidor JavaScript en producción también.

Eso tiene mucho sentido si realmente quiero un backend de Node. Hay una ventaja genuina en tener un lenguaje y herramientas estrechamente relacionadas en ambos lados de la conexión. Si mi equipo quiere TypeScript en todas partes, esa es una arquitectura perfectamente coherente.

Yo no.

Elegí FastAPI porque quiero escribir el backend en Python. Instalar otro runtime junto a él solo para entregar activos de frontend se siente como contratar a un segundo chef para llevar platos de la cocina al comedor.

Imagen
¿Quiero gigabytes de node_modules y esto en mi servidor de producción? No.

También está el pequeño asunto del universo de dependencias de JavaScript. Es demasiado pesado, mantiene poca compatibilidad y a menudo está roto. Aunque nvm Puede instalar fácilmente la versión correcta de Node, pero aún así ocupa una gran cantidad de espacio que los servidores alojados a menudo no tienen.

Node es útil en mi máquina de desarrollo. Vite es excelente. create-vue Es excelente. El ecosistema de compilación hace su trabajo extremadamente bien.

Eso no significa que quiera nada de eso en la máquina de producción.

Opción 2: renderizar todo en el servidor

En el extremo opuesto, puedo omitir el SPA por completo y generar HTML en Python.

Esto merece más respeto del que a veces recibe. No todas las aplicaciones necesitan un tiempo de ejecución de la aplicación del lado del cliente, un enrutador y varios megabytes de civilización de apoyo.

Herramientas como htmx pueden llevar el HTML renderizado por el servidor sorprendentemente lejos al agregar solicitudes HTTP, intercambios, transiciones, WebSockets y eventos enviados por el servidor directamente a través de atributos HTML. Combínalo con html5tagger para crear esos documentos y fragmentos de HTML en el servidor, y tendrás un sitio que funciona en todas partes y que puede ser leído por redes sociales, motores de búsqueda y agentes por igual.

Para sitios dominados por documentos, formularios e interacciones relativamente simples, me gusta esta arquitectura. El navegador solicita algo, Python produce HTML, y nadie necesita una pipeline de compilación capaz de lanzar una sonda a Marte.

Vasanko.com se basa en este método, solo incorporando Vue para la interfaz de administración donde se requiere una mayor interactividad. Este CMS se ejecuta en la configuración de FastAPI-Vue, pero renderiza todas las páginas del lado del servidor en Python.

Opción 3: ejecutar dos servidores

Por lo tanto, el compromiso común es:

  • FastAPI ejecuta la API.
  • Vite u otro servidor JavaScript ejecuta el frontend
  • Un proxy inverso pone ambos bajo un único nombre de host.
  • La producción ahora tiene dos aplicaciones, dos pilas de dependencias, dos procesos y otro archivo de configuración que mantiene unida la combinación.

Esto funciona, pero no es muy bonito.

Al navegador no le importa si app.js Fue emitido por Python, Node, Caddy, nginx o una tostadora suficientemente decidida. Una vez que se ha construido el frontend, el resultado es HTML estático, CSS, JavaScript, fuentes e imágenes.

¿Entonces, por qué mantener la fábrica en funcionamiento después de que el producto ya haya salido de la línea de ensamblaje?

Construye con JavaScript, ejecuta con Python

Eso se convirtió en la idea central detrás de fastapi-vue-setup.

Quiero herramientas de JavaScript donde realmente sean útiles:

  • create-vue para crear el frontend
  • Vite para el servidor de desarrollo
  • Recargas instantáneas en caliente tras los cambios
  • La compilación normal de Vue en Node, Bun o Deno

Y luego quiero que desaparezca.

El artefacto de producción debería ser un paquete de Python que contenga un frontend ya construido. La instalación de ese paquete no debería requerir Node, npm, Vite, el código fuente de Vue, ni la anomalía gravitacional tradicionalmente almacenada bajo node_modules.

Esa es exactamente la forma en que fastapi-vue-setup Construye proyectos hoy: uv build Ejecuta la compilación del frontend e incluye los activos resultantes dentro del paquete de Python. La configuración de Hatch generada trata frontend-build Como un artefacto y engancha la compilación de la distribución de código fuente, al tiempo que limita el contenido del paquete al propio paquete de Python.

La distinción es especialmente importante para un sdist. No quiero que una distribución de código fuente signifique “aquí hay un poco de Python, aquí hay un árbol de desarrollo de Vue completo, ahora por favor instala Node y reconstruye la aplicación real tú mismo”. El frontend ya está compilado antes de que la distribución salga de mi máquina.

El paquete contiene lo que necesita para funcionar, no todo lo que necesité para construirlo.

Eso hace que el despliegue parezca maravillosamente aburrido:

uvx my-app

No hay ceremonia de instalación de Node en la máquina objetivo. No npm install. Ningún servidor de frontend. Ningún árbol de dependencias de JavaScript que se despierte tres meses después y pida ser alimentado.

El paquete inicia FastAPI, y FastAPI sirve la aplicación.

El otro problema feo

Construir el frontend era solo la mitad del trabajo.

StaticFiles no es exactamente un servidor de frontend

FastAPI expone los de Starlette StaticFiles, y para los activos estáticos ordinarios hace exactamente lo que dice en la descripción:

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

El problema comienza cuando el frontend es el sitio en sí.

Una aplicación Vue normalmente quiere /. También puede querer /login, /settings, /dashboard/coffee-reactor/7, y cualquier otra cosa que sea propiedad del enrutador del lado del cliente.

Pero montarlo StaticFiles En / Efectivamente, montar la aplicación en todo el espacio URL restante. El propio mantenedor de FastAPI explicó el problema hace años: montarla en la raíz y la aplicación estática se hace cargo, por lo que las operaciones de ruta normales debajo de ella ya no funcionan como se esperaba.

Y necesitamos:

  • Construcción de frontend en /*
  • FastAPI todavía maneja
    • /api/...
    • /openapi.json
    • Cualquier otra ruta arbitraria

Este no es el mismo problema que servir /static/logo.svg.

FastAPI ha mejorado recientemente su propio soporte frontend, y la documentación actual ahora apunta explícitamente a las aplicaciones frontend hacia app.frontend() En lugar de simplemente StaticFilesPero fastapi-vue Precede a esa solución y también tiene una función algo diferente: es la pequeña parte de tiempo de ejecución de este sistema de empaquetado completo.

Tiempo de ejecución de fastapi-vue

El compañero fastapi-vue El paquete proporciona un Frontend Manejador en lugar de montaje StaticFiles Sobre la aplicación.

En modo SPA, puede devolver index.html Para las rutas que pertenecen al enrutador del lado del cliente en lugar de requerir un archivo físico con ese nombre.

Note

Debido a cómo funciona el enrutamiento de FastAPI, los montajes de aplicaciones se comen todo bajo esa ruta. El resto de las rutas se prueban en orden y la primera gana. Por lo tanto, en el modo SPA debemos colocar el catch-all al final del módulo de la aplicación.

Con el modo SPA deshabilitado, solo se vincula a las rutas de los archivos reales, lo que permite que tus rutas después de eso aún capturen lo que se desvía.

También se encarga de los detalles menos glamurosos que no me apetece particularmente volver a implementar cada martes:

  • ETag y Last-Modified
  • Almacenamiento en caché inmutable para activos construidos
  • Almacenamiento en caché de RAM con compresión zstd
  • Redireccionamiento SPA de respaldo y /favicon.ico Cuando sea necesario
  • No sirvas una compilación obsoleta accidental en modo de desarrollo

Esta es la dependencia de tiempo de ejecución de la producción. Es pequeña y solo para Python.

Toda la maquinaria para construir y desarrollar la aplicación Vue permanece en el proyecto fuente.

Ingresa fastapi-vue-setup

Con esas piezas en su lugar, fastapi-vue-setup Está principalmente preocupado con eliminar el cableado repetitivo.

El comando básico es deliberadamente poco emocionante: apúntalo a tu carpeta de aplicaciones, o . Si ya estás allí.

uvx fastapi-vue-setup my-app

Necesitas cambiar los números de puerto que tu backend de producción, Vite y desarrollo usan por defecto? Ejecuta con --ports. Sin eso, conserva los puertos que previamente habías configurado. Y siempre puedes --listen En tu CLI o scripts/devserver.py Para cambiar eso en tiempo de ejecución.

Pero hay dos casos bastante diferentes que se esconden detrás de ello.

Y proporciona utilidades de soporte para el punto de entrada CLI que obtiene tu aplicación, que también puede tomar tus propias opciones de línea de comandos, algo que fastapi run No puede proporcionarlo.

Creando una nueva aplicación

Para un nuevo proyecto, no quiero fastapi-vue-setup Para un nuevo proyecto, no quiero imponer una plantilla Vue congelada de mi propia creación. Quiero que cree un proyecto Python configurado con el nombre que le di, y la configuración de Vue que elija:

  • JavaScript o TypeScript
  • Vue Router o sin router
  • Pinia o no
  • Pruebas, linting y opciones de formato
  • Las otras opciones apoyadas por el actual create-vue

La herramienta entonces construye la integración de FastAPI alrededor de la aplicación que el desarrollador realmente eligió.

Esto es importante porque una plantilla inevitablemente fosiliza las preferencias de alguien. Seis meses después, su idea de una pila completa moderna puede ya pertenecer a una exposición de museo, y tú estás atrapado con lo que tienes.

Preferiría tener la opción.

La configuración está completa

¿Ya tienes una app?

Aquí puede que ya tenga un proyecto real que contiene código que preferiría no vaporizar. Se puede crear con el mismo script o de forma independiente, y el script lo parcheará donde sea necesario.

El script de configuración detecta el proyecto de Python y el módulo de backend, detecta o crea el frontend de Vue, y corrige las piezas que puede integrar de forma segura con cambios mínimos.

Note

Mueve tu Vue existente completamente debajo de frontend/ Primero. Colocamos Vue allí para evitar contaminar la raíz con cosas de Node. Lo colocamos allí para que el script modifique la aplicación existente en lugar de crear una nueva.

Necesitas actualizar a la última versión? Simplemente ejecuta fastapi-vue-setup De nuevo, y actualizará las nuevas características que tiene.

Esa es una de las principales diferencias entre esto y un repositorio de plantillas.

Una plantilla dice:
Clona este repositorio para comenzar tu proyecto

Necesitaba herramientas que también pudieran decir:
Bien, ya estás en 30.000 líneas. Muéstreme dónde está el paciente.

Tu aplicación está lista para ejecutarse

uv run scripts/devserver.py

vite.config.js

Configure qué rutas se proxifican al backend. Por defecto, esto solo /apiEsta configuración solo afecta a la configuración de desarrollo, en producción todo se redirecciona a FastAPI.

TIEMPO DE EJECUCIÓN DE JS

Entorno con valor bun/deno/node o ruta a uno de ellos (de lo contrario, encontramos uno).

Eso inicia el servidor de desarrollo Vue/Vite y FastAPI con soporte de recarga. La integración de Vite generada redirecciona las solicitudes de back-end al servidor de desarrollo de Python. Tu navegador se conecta a Vite.

Así que durante el desarrollo todavía obtengo las cosas que realmente me gustan del ecosistema de JavaScript.

Hola mundo, conectando FastAPI

Cuando el desarrollo esté terminado:

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

Vue se compila, el resultado se integra en la distribución de Python, y la maquinaria de compilación ha completado su misión. Puedes uv publish Tu paquete, si así lo deseas, o simplemente cópialo a prod desde dist/Luego, instala y ejecuta con:

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

Todo lo que necesitaba instalar de antemano era UV Y en el sistema de desarrollo Node En sí mismo. No necesitaba tocar npm En absoluto, y ahora puedo instalarlo o ejecutarlo en otro lugar sin llevar el taller de JavaScript junto conmigo.

Una aplicación, por fin

Lo que en última instancia quería no era particularmente exótico.

  • Quería escribir el backend en Python.
  • Quería escribir el frontend en Vue.
  • Quería Vite mientras lo desarrollaba.

Y quería configurar e implementar una cosa rápidamente.

No es una aplicación de Python más una aplicación de JavaScript. No son dos contenedores unidos por nginx y sospecha mutua.

A <1MB Python package that Simplemente funciona ™.

Contiene el frontend. FastAPI lo sirve desde la raíz del sitio sin engullir el resto de la aplicación. El enrutamiento de Vue funciona cuando quiero una SPA, y el enrutamiento de archivos simples permite que mi backend mantenga los catch-alls para sí mismo, por ejemplo, manejando cualquier URL bonita con contenido renderizado del lado del servidor como en este sitio. A su vez, puede usar Vue en los lugares que necesita, dos mundos en perfecta armonía.

La cadena de herramientas de JavaScript hace lo que se supone que debe hacer una cadena de herramientas:

Espera, construye el software y luego se aparta del camino.

A continuación, tu pila completa necesita una base de datos y Kanta te tiene cubierto. Con esta cadena de herramientas, tendrás tu aplicación funcionando en muy poco tiempo.