web-dev-qa-db-ja.com

Flaskでcreate-react-appを提供する

flaskバックエンドとAPIルートがあり、React create-react-appボイラープレートを使用して作成された単一ページアプリケーション。 create-react-app組み込みのdevサーバー、my Flaskバックエンドは動作しますが、問題ありません。

今、私は(npm run build)my Flask server。からの静的な反応アプリ。反応アプリを構築すると、次のディレクトリ構造になります。

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

これにより、静的アセットが正常に提供されます。しかし、それは非常にエレガントなソリューションではありません。

一方、これを組み込みのflask静的ユーティリティに組み込むことができます。しかし、これを設定する方法がわかりません。

静的フォルダーを非常に特定の不便な方法で構造化することを余儀なくされているため、これをどのように処理するのか本当にわかりませんが、create-react-appの使用を再考するようになります:アプリがサーバーに静的コンテンツを要求する方法を変更する必要があります。

全体:私のソリューションは十分堅牢ですか?組み込みのflask機能を使用してこれらのアセットを提供する方法はありますか?create-react-appを使用するより良い方法はありますか?任意の入力を歓迎します。必要に応じて詳細情報を提供できます。

読んでくれてありがとう !

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)

それが私がやったことです。そのため、基本的にすべてのルートをキャッチし、パスがファイルであるかどうかをテストします。こうすることで、任意のルートから反応アプリをリロードでき、壊れることはありません。

50
Jodo

最初に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')

残念ながら、開発ホットリロードで動作させることはできないと思います。

5
Pranay Aryal

受け入れられた答えは私にはうまくいきません。利用した

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