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

Serving a front end created with create-react-app with Flask

我有一个带有 API 路由的 Flask 后端,这些路由由使用 create-react-app 创建的 React 单页应用程序访问。使用 create-react-app 开发服务器时,我的 Flask 后端可以正常工作。

我想从我的 Flask 服务器提供构建的(使用 npm run build)静态 React 应用程序。构建 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-react-app?

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。这样你就可以从你希望的任何路径重新加载反应应用程序并且它不会中断。

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

不幸的是,我不认为你可以让它与开发热重载一起工作。

已接受的答案对我不起作用。我用过

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


这里有一个可行的解决方案。 有没有想过为什么 statictemplates 我们需要两个单独的文件夹。把乱七八糟的东西分开,对吧? 但是,这是生产构建的一个问题,因为它有一个文件夹用于 statictemplates 类型的文件,并且所有依赖项都是这样链接的。

如果您同时考虑 statictemplates,将提供 build 文件夹。

使用这样的东西

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

您的 Flask 应用 运行 没问题。

我使用了一个只有一个 route / 的 flask 服务器,它从 Create react app(CRA)

的构建文件夹中读取 index.html 文件
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()

这样设置我遇到了错误,静态文件由于路径不匹配而无法正常提供,所以我使用的解决方案是

  1. 在CRA的package.json中添加主页属性并设置为"/static"

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

 Add **homepage** key parallel to the **dependencies** key in the package.json file
  1. 主页 属性将在CRA的构建过程中使用,并用于代替%PUBLIC_URL% index.html 并附加到其他静态资产 URL 路径(您可以在构建过程后通过查看 index.html 代码来验证)

  2. 在构建过程之后,运行 flask 服务器,我们可以看到第一次带有 / 的 GET 请求和 index.html 将被服务,随后是请求 /static/static/js/[[filename]] 来自 [=52= 的其他静态资产] 文件,一切正常