En primer lugar, solo quería decir que este es mi primer proyecto de aplicación web. Pasé los últimos días tratando de encontrar respuestas sobre cómo unir esencialmente el frontend y el backend. Tengo muchas preguntas, pero la principal que quiero que me respondan es cómo devolver mi 'producto final' de frontend desde un punto final de backend.
Esto es lo que entiendo (corregidme si me equivoco):
Luego viene el siguiente problema:
Cuando quiero probar mi interfaz y ver cómo va, simplemente ejecuto npm run start . Luego voy a la URL dada (generalmente http://localhost:8080/ ) y tengo acceso a la interfaz que he desarrollado. Y cuando quiero implementarlo, ejecuto npm run build , lo que me da una carpeta dist (agrupada y minimizada).
Si quiero ejecutar y probar mi backend localmente, ya que estoy usando FastAPI , simplemente ejecuto uvicorn main:app --reload .
¿Cómo poner los dos juntos? Más específicamente, en mi código de backend, ¿cómo devuelvo el producto de mi trabajo de frontend (es decir, la carpeta dist ?). He intentado lo siguiente (simplificado):
@app.get("/", response_class=HTMLResponse) def root(): return open("../frontend/dist/index.html", "r").read()pero, por supuesto, esto solo me da el html estático sin los componentes de React.
Me doy cuenta de que esta publicación puede estar cargada de suposiciones incorrectas y malas prácticas (en cuyo caso, ¡mis disculpas! y agradecería cualquier corrección/sugerencia). Sin embargo, si pudieran responder las siguientes preguntas, lo agradecería mucho. Estas son preguntas que tengo y que espero me ayuden a probar toda mi aplicación web localmente en mi computadora.
GET en el extremo raíz del dominio?www.example.com/A , www.example.com/B y www.example.com/C , ¿debo crear ¿Tres proyectos frontend React separados? Es decir, ¿equivalente a tener tres carpetas dist ? ¿Cuál es la forma estándar en que se maneja esto?El enfoque "tradicional" para ejecutar una aplicación web es tener un servidor que sirva su aplicación web (es decir, su aplicación React). Por lo general, escuchará que nginx se usa como el servidor web que se usa para las aplicaciones modernas de una sola página. Cuando ejecuta npm run start , inicia un servidor local en su máquina y hace que su aplicación esté disponible en http://localhost:8080 (el puerto y el nombre de host son, por supuesto, configurables).
Cuando se trata de su API, debe ser su propio servidor disponible en un punto final/url diferente, y luego su aplicación web realizará llamadas API a ese punto final/url para obtener datos.
Por la forma en que describe las cosas, parece que está tratando de usar FastAPI para renderizar su aplicación web en el servidor, pero no estoy seguro de cuán factible es eso, especialmente considerando que hay un marco completo dedicado exclusivamente a las aplicaciones de reacción de renderizado del servidor. .
Estas son buenas preguntas y ciertamente es posible. Te diré lo que hago, con la advertencia de que puede haber una mejor manera...
Estoy usando Vue en lugar de React, pero su proceso de compilación también envía html, js y css estáticos a un directorio dist/ , por lo que el proceso debería ser más o menos el mismo.
Primero puede copiar el archivo dist/index.html que menciona en su directorio de templates/ FastAPI. Utilizará su ruta FastAPI para servir ese archivo como plantilla.
Luego copie su js y css en un directorio static/ y asegúrese de que FastAPI conozca tanto las estáticas como las plantillas.
from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") @app.get("/") async def serve_spa(request: Request): return templates.TemplateResponse("index.html", {"request": request}) Es posible que deba configurar algo en React para que su compilación sepa que js y css vivirán en un directorio llamado static . Para Vue, existe la opción assetsDir dentro de vue.config.js
Para su pregunta sobre el manejo de diferentes rutas, como example.com/a y example.com/b , depende de cómo desee manejar esas solicitudes. ¿Quiere que su única aplicación de reacción maneje todas esas rutas?
Si ese es el caso, es posible que desee ver también: ¿Cómo capturar rutas arbitrarias en una ruta en FastAPI?
Una opción es copiar la ruta de serve_spa() arriba y manejar sus rutas, como /a , /b , etc.
O use una ruta general:
@app.route("/{full_path:path}") async def catch_all(request: Request, full_path: str): print("full_path: "+full_path) return templates.TemplateResponse("index.html", {"request": request})También he tenido problemas con esto y aquí hay un enfoque que funcionó para mí.
import logging from fastapi import FastAPI from starlette.responses import RedirectResponse from starlette.staticfiles import StaticFiles app = FastAPI() @app.get("/") async def index(): return RedirectResponse(url="/index.html") app.mount("/", StaticFiles(directory="backend/ui/"), name="ui")Nota: tenga en cuenta que
app.mountse llama después de registrar la ruta/. Según mi experiencia, si se llama al montaje antes del registro, simplemente no se redirigirá aindex.html
Nota: utilizo
react-scriptspara generar la aplicación.