使用 Flask 为用 create-response-app 创建的前端提供服务

我有一个 Flask 后端的 API 路由,可以通过使用 create-response-app 创建的 React 单页应用程序访问。当使用 create-response-app dev 服务器时,我的 Flask 后端可以正常工作。

我想服务建立(使用 npm run build)从我的 Flask 服务器静态反应应用程序。构建 React 应用程序会导致以下目录结构:

- 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 静态实用程序结合起来。但是我不知道如何配置它。

我的解决方案是否足够稳健?是否有一种方法可以使用内置的 Flask 特性来服务这些资产?有没有更好的方法来使用 create-response-app?

40660 次浏览
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)

Thats what I ended up with. So bascially catch all routes, test if the path is a file => send file => else send the index.html. That way you can reload the react app from any route you wish and it does not break.

First do npm run build to build the static production files as mentioned by you above

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


Unfortunately, I don't think you can get it work with the development hot-reload.

The accepted answer does not work for me. I have used

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




A working solution here. Ever thought why we need two separate folders for static and templates. To segregate the mess, right? But, it's a problem with the production build since it has one folder for both static and templates type of files and all dependencies are linked like that.

The build folder will be served if you consider it both static and templates.

Use something like this

from flask import Flask, render_template


app = Flask(__name__, static_url_path='',
static_folder='build',
template_folder='build')


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


Your flask app will run fine.

I used a flask server with only one route / which read the index.html file from the build folder of Create react app(CRA)

from flask import Flask
app = Flask(__name__)
app.static_folder =  '../build'


@app.route('/')
def index():
fref = open(r'../build/index.html')
html_text = fref.read()
fref.close()
return html_text


app.run()

Setting up this way I faced an error, the static files are not properly served due to path mismatch, so the solution I used is

  1. Add a homepage property in package.json of CRA and set it to "/static"

{ "name":"App-name", "version":"", "dependencies":{} "homepage":"/static",....[other keys]}

 Add **homepage** key parallel to the **dependencies** key in the package.json file
  1. This homepage property will be used during the build process of CRA and used in the place of %PUBLIC_URL% of index.html and gets appended to other static assets URL path (you can verify by viewing the index.html code after the build process)

  2. After the build process, run the flask server,we can see the GET request coming with / for the first time and index.html will be served and followed by requests /static/static/js/[[filename]] for other static assets from HTML file and everything works correctly