web-dev-qa-db-fra.com

Servir une application créer-réagir avec Flask

J'ai un back-end flask) avec les routes de l'API auxquelles on accède par une application React, créée à l'aide du passe-partout create-react-app. Lorsque vous utilisez le serveur de développement intégré de create-react-app, mon arrière-plan Flask) fonctionne, pas de problème avec cela.

Maintenant, je voudrais servir le construit (en utilisant npm run build) application statique de réaction depuis mon serveur Flask. La construction de l’application réagissant conduit à la structure de répertoire suivante:

- build
  - static
    - css
        - style.[crypto].css
        - style.[crypto].css.map
    - js
        - main.[crypto].js
        - main.[crypto].js.map
  - index.html
  - service-worker.js
  - [more meta files]

Par [crypto], j'entends les chaînes générées aléatoirement générées au moment de la construction.

Après avoir reçu le index.html _, le navigateur effectue alors les requêtes suivantes:

- GET /static/css/main.[crypto].css
- GET /static/css/main.[crypto].css
- GET /service-worker.js

Ma question est alors: comment dois-je m'occuper de ces fichiers? Je suis venu avec ceci:

from flask import Blueprint, send_from_directory

static = Blueprint('static', __name__)

@static.route('/')
def serve_static_index():
    return send_from_directory('../client/build/', 'index.html')

@static.route('/static/<path:path>') # serve whatever the client requested in the static folder
def serve_static(path):
    return send_from_directory('../client/build/static/', path)

@static.route('/service-worker.js')
def serve_worker():
    return send_from_directory('../client/build/', 'service-worker.js')

Ainsi, les actifs statiques sont servis avec succès. Mais ce n'est pas une solution très élégante.

D'autre part, je pourrais incorporer cela aux utilitaires statiques intégrés flask. Mais je ne comprends pas comment configurer cela.

Je ne sais vraiment pas comment gérer cela, au point que cela me fait reconsidérer mon utilisation de create-react-app, car cela me force à structurer mon dossier statique de manière très spécifique et inopportune: moi de changer la façon dont l’application demande du contenu statique au serveur.

Globalement: ma solution est-elle suffisamment robuste? Existe-t-il un moyen d'utiliser les fonctionnalités flask intégrées) pour servir ces actifs? Existe-t-il un meilleur moyen d'utiliser create-react-app? Toute contribution est appréciée. Je peux fournir plus d'informations si nécessaire.

Merci d'avoir lu !

45
Theo
import os
from flask import Flask, send_from_directory

app = Flask(__name__, static_folder='react_app/build')

# Serve React App
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def serve(path):
    if path != "" and os.path.exists(app.static_folder + path):
        return send_from_directory(app.static_folder, path)
    else:
        return send_from_directory(app.static_folder, 'index.html')


if __== '__main__':
    app.run(use_reloader=True, port=5000, threaded=True)

C'est ce que j'ai fini avec. Donc, essentiellement, attrapez tous les itinéraires, testez si le chemin est un fichier => send file => else envoyez le fichier index.html. De cette façon, vous pouvez recharger l'application de réaction de n'importe quel itinéraire que vous souhaitez et cela ne casse pas.

50
Jodo

Tout d'abord faire npm run build pour construire les fichiers de production statiques mentionnés ci-dessus

from flask import Flask, render_template

app = Flask(__name__, static_folder="build/static", template_folder="build")

@app.route("/")
def hello():
    return render_template('index.html')

print('Starting Flask!')

app.debug=True
app.run(Host='0.0.0.0')

Malheureusement, je ne pense pas que vous puissiez le faire fonctionner avec le rechargement à chaud du développement.

5
Pranay Aryal

La réponse acceptée ne fonctionne pas pour moi. j'ai utilisé

import os

from flask import Flask, send_from_directory, jsonify, render_template, request

from server.landing import landing as landing_bp
from server.api import api as api_bp

app = Flask(__name__, static_folder="../client/build")
app.register_blueprint(landing_bp, url_prefix="/landing")
app.register_blueprint(api_bp, url_prefix="/api/v1")


@app.route("/")
def serve():
    """serves React App"""
    return send_from_directory(app.static_folder, "index.html")


@app.route("/<path:path>")
def static_proxy(path):
    """static folder serve"""
    file_name = path.split("/")[-1]
    dir_name = os.path.join(app.static_folder, "/".join(path.split("/")[:-1]))
    return send_from_directory(dir_name, file_name)


@app.errorhandler(404)
def handle_404(e):
    if request.path.startswith("/api/"):
        return jsonify(message="Resource not found"), 404
    return send_from_directory(app.static_folder, "index.html")


@app.errorhandler(405)
def handle_405(e):
    if request.path.startswith("/api/"):
        return jsonify(message="Mehtod not allowed"), 405
    return e


0
Lukasz Madon