将反应应用程序的构建包含到Flask中的正确方法

时间:2018-01-24 23:53:53

标签: python python-3.x reactjs flask

我有一个完全使用烧瓶开发的网站。它使用名为dashboards的蓝图,该蓝图托管一些视图以访问不同的可视化,即dashboards/<string: dashboard_name>

我使用idname及其所属的group存储我的信息中心,因此用户只能访问他们所属的组中的可视化。

(这是我解决这个问题的经验不足的方法,所以我也愿意接受更好的设计模式的建议来实现这个目标。)

我的项目看起来像这样

app
├── dashboards
│   ├── __init__.py
│   └── views.py
├── __init__.py
├── models
│   ├── dashboard.py
│   └── __init__.p
├── static
│   ├── css
│   │   ├── styles.css
│   └── js
│       └── scripts.js
└── templates
    ├── base.html
    └── dashboards
        ├── cat.html
        ├── clock.html
        ├── index.html
        ├── private.html
        └── public.html

我对Dashboard蓝图的看法

# app/dashboards/views.py

from ..models.dashboard import Dashboard

@dashboards.route('/<string:name>')
def view_dashboard(name):
    # a dictionary with dashboards available to current_user
    dashboards = get_dashboards() 

    for dashboard in dashboards.values():
        for d in dashboard:
            if name == d.name:
                route = 'dashboards/{dashboard}.html'.format(dashboard = d.name)
                return render_template(route, dashboard=d)
    else:
        return render_template('404.html'), 404

和仪表板蓝图

# app/dashboards/__init__.py

from flask import Blueprint

dashboards = Blueprint('dashboards', __name__)

from . import views

最后,我使用了create_app模式

# app/__init__.py

# some imports happening here

def create_app(config_name):
    app = Flask(__name__)

    from .dashboards import dashboards as dashboards_blueprint
    app.register_blueprint(dashboards_blueprint, url_prefix='/dashboards')

    return app

高于app的一个级别,有manage.py调用create_app方法,传递一些配置属性。我相信这是Flask的常见模式。我也相信这与我的问题无关。

特别是,如果使用create-react-app软件包部署react应用程序,即使用npm run build,则输出是一个文件夹/build,其中包含运行应用程序所需的静态文件。该文件夹具有例如以下结构

├── build
│   ├── asset-manifest.json
│   ├── favicon.ico
│   ├── index.html
│   ├── manifest.json
│   ├── service-worker.js
│   └── static
│       ├── css
│       │   ├── main.<some-hash-1>.css
│       │   └── main.<some-hash-1>.css.map
│       └── js
│           ├── main.<some-hash-2>.js
│           └── main.<some-hash-2>.js.map
other files here

现在如果想使用Flask插入这个react-app,我现在要做的是将/css/js /build中的文件移动到/static文件夹在/app内,并从index.html重命名为/build,让我们说'react-dashboard.html'并将其移至templates/dashboards

这是使基本应用程序正常工作的一种非常愚蠢的方法,但我不知道从/build放置其他文件的位置,以免出现更好的设计模式。

从此README我得到了我可以调整蓝图定义并将我的模板和静态文件夹移到app/dashboards中,但我仍然不知道其他文件在哪里service-worker.js,和清单等等。

在我的Flask应用程序上“装载”部署的反应应用程序的正确方法是什么?我知道重新组织/build中的文件是不可取的。

1 个答案:

答案 0 :(得分:0)

我已经解决了调整蓝图的问题

bp = Blueprint(name='myblueprint', 
                    import_name=__name__,
                    static_folder='static/myblueprint',
                    template_folder='templates',
                    static_url_path='/static', # this is what myblueprint.static will point to
                    url_prefix='/myblueprint', 
                    subdomain=None,
                    url_defaults=None, 
                    root_path=None)

有了这个,蓝图中的静态路径将指向/myblueprint/static,我将需要修改我的create-react-app构建文件夹。

  • static中的每个* .css,* .js和.html中的/build调用替换为/myblueprint/static
  • 重新排列/build内的文件夹以匹配我的蓝图static文件夹。
    • /build/static移至/blueprint/static
    • /blueprint/templates/index.html中设置我自己的jinja模板,调用这些文件。确保此文件指向/myblueprint/static中的静态资源,而不指向/build/static

我已经创建了一个gulpfile来自动执行此过程,

var gulp = require('gulp');
var replace = require('gulp-replace');
var rename = require('gulp-rename');

// script to deploy react build into flask blueprint directory
// it replaces values and folder names

// README
// how to use this:
// in the react app, run npm run build
// copy the resulting /build folder in /myblueprint
// create a template of a template in /templates/base as index.default.html

// install gulp, gulp-replace, gulp-rename
// run gulp from /myblueprint


// replace routes inside css files

gulp.task('othertemplates', function(){
  gulp.src(['./build/static/css/main.*.css'])
    .pipe(replace('url(/static/media/', 'url(/myblueprint/static/media/'))
    .pipe(gulp.dest('static/myblueprint/css/'));
});

// replace routes inside js files

gulp.task('jsthingtemplates', function(){
  gulp.src(['./build/static/js/main.*.js'])
    .pipe(replace('static/media/', 'myblueprint/static/media/'))
    .pipe(gulp.dest('static/myblueprint/js/'));
});

// move other files

gulp.task('mediastuff', function(){
  gulp.src(['./build/static/media/*'])
    .pipe(gulp.dest('static/myblueprint/media/'));

  gulp.src(['./build/asset-manifest.json'])
    .pipe(gulp.dest('static/myblueprint/'));
});

// replace hashes in assets in the jinja template

gulp.task('jinjareplace', function(){

  var fs = require('fs');
  var assets = JSON.parse(fs.readFileSync('./build/asset-manifest.json'));

  // extract hashes

  let jsHashNew = assets['main.js'].match('[a-z0-9]{8}')
  let cssHashNew = assets['main.css'].match('[a-z0-9]{8}')

  gulp.src(['./templates/myblueprint/base/index.default.html'])
    .pipe(replace('css/main.cssHash.css', `css/main.${cssHashNew}.css`))
    .pipe(replace('js/main.jsHash.js', `js/main.${jsHashNew}.js`))
    .pipe(rename('index.html'))
    .pipe(gulp.dest('templates/myblueprint/'));
});


gulp.task('default', ['othertemplates', 'jsthingtemplates', 'mediastuff', 'jinjareplace'])

有了这个,您可以从与gulp相同的路径运行gulpfile.js,并且应该涵盖所有内容。