Обслуживание приложения-реагирования-приложения с Flask

У меня есть флеш-back-end с API-маршрутами, к которым обращается одностраничное приложение React, созданное с использованием шаблона create-response-app. При использовании встроенного сервера разработчиков create-response-app мой конец флешки работает, без проблем.

Теперь я хотел бы использовать встроенное (используя npm run build) статическое приложение для реагирования с моего сервера Flask. Создание реактивного приложения приводит к следующей структуре каталогов:

- 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]

С помощью [crypto] я имею в виду случайно сгенерированные строки, сгенерированные во время сборки.

Получив файл index.html, браузер затем выполнит следующие запросы:

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

Теперь мой вопрос: как я должен обслуживать эти файлы? Я придумал это:

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')

Таким образом, статические активы успешно обслуживаются. Но это не очень изящное решение.

С другой стороны, я мог бы включить это со встроенными статическими утилитами. Но я не понимаю, как это настроить.

Я действительно не знаю, как справиться с этим, до такой степени, что это заставляет меня пересмотреть мое использование приложения create-response-app, поскольку оно заставляет меня структурировать мою статическую папку очень неудобным образом: я не могу изменить, как приложение запрашивает статический контент с сервера.

В целом: Является ли мое решение достаточно надежным? Есть ли способ использовать встроенные функции флагов для обслуживания этих активов? Есть ли лучший способ использовать приложение create-react-app? Любой вход оценивается. При необходимости я могу предоставить дополнительную информацию.

Спасибо за чтение!

Ответ 1

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 __name__ == '__main__':
    app.run(use_reloader=True, port=5000, threaded=True)

Это то, что я закончил. Таким образом, в основном перехватите все маршруты, проверьте, является ли путь файлом => отправить файл => иначе отправьте index.html. Таким образом, вы можете перезагрузить приложение реакции с любого маршрута, который вам нужен, и он не сломается.

Ответ 2

Сначала выполните npm run build чтобы собрать статические производственные файлы, как вы упоминали выше.

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')

К сожалению, я не думаю, что вы можете заставить его работать с горячей перезагрузкой разработки.

Ответ 3

Принятый ответ не работает для меня. Я использовал

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