Fullstack Python web app: Flask & React & Webpack
Introduction
Le monde du développent des sites web est tellement vaste que chaque jour nous, les développeurs, sommes amenés à utiliser/apprendre des nouvelles technologies.
La tendance à la mode, aujourd’hui, c’est du faire des SPA (Single Page Application) en utilisant, généralement, React, Angular et VueJS (je note aussi Svelte) frameworks.
Cependant, comme étant un développeur Python à la base, j’ai cherché sur net un tutoriel qui étale comment on devra procéder pour créer un site web en utilisant Flask
et React
.
Hélas, tout ce que j’ai trouvé ce sont soi des tutoriels qui utilisent deux serveurs web l’un pour Flask
et l’autre pour React
et que dans le passage en PROD
on devra simuler le meme environnement, ou bien des tutoriels qui fonctionnent pas.
Pour moi, ce genre d’approche n’est pas la bonne, à vous de voir si ça vous convient ou pas. Mais personnellement je ne veux pas gérer deux environnements différents et surtout ne pas gérer deux serveurs web différents.
C’est pour cela je me suis dit qu’il est temps que j’écris ce tutoriel pour vous montrer une autre approche d’utilisation de ces frameworks pour faire du SPA et les intégrer avec une app Flask
et servir le tour dans un seul environnement et surtout avec un seul serveur web.
Installation
Pour commencer, on va créer un virtalenv
pour notre app en Flask
:
$> mkdir flask_react
$> cd flask_react
$> virtualenv venv
$> source venv/bin/activate
$> pip install flask
(venv)$>
Ensuite on doit installer NodeJS
, NPM (>=v8)
React app et Webpack
:
(venv)$> npm init react-app frontend
Ensuite on va installer Webpack
et Webpack-cli
:
(venv)$> cd frontend
(venv)$> npm install --save-dev webpack
(venv)$> npm install --save-dev webpack-cli
(venv)$> npm i @babel/core babel-loader @babel/preset-env @babel/preset-react babel-plugin-transform-class-properties --save-dev
Maintenant, nous devons modifier le fichier packages.json
comme suit:
"scripts": {
"dev": "webpack --mode development ./src/index.js --output ./compiled/bundles.js",
"build": "webpack --mode production ./src/index.js --output ./compiled/bundles.js",
"watch": "webpack --watch --mode development ./src/index.js --output ./compiled/bundles.js"
},
Et ajouter un fichier .babelrc
avec ce contenu:
{
"presets": [
"@babel/preset-env", "@babel/preset-react"
],
"plugins": [
"transform-class-properties"
]
}
Ensuite installer Webpack live reload plugin
, CSS loader
et SVG loader pour React
:
(venv)$> npm install --save-dev webpack-livereload-plugin
(venv)$> npm install --save-dev css-loader
(venv)$> npm install svg-inline-loader react-inlinesvg --save-dev
Finalement, on doit ajouter un fichier nommé webpack.config.js
et on ajoute dedans:
var LiveReloadPlugin = require('webpack-livereload-plugin');
module.exports = {
plugins: [
new LiveReloadPlugin()
],
watchOptions: {
ignored: /node_modules/
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.svg$/,
loader: 'svg-inline-loader'
}
]
}
};
Ajouter le bundle.js
à notre Flask
app
À ce niveau on a configuré React
et Webpack
, ce qu’il nous reste à faire c’est de configurer Flask
pour qu’il puisse lire le fichier JS
compilé et l’ajouter comme un fichier statique à index.html
.
Pour le faire, on va modifier un peu le fichier public/index.html
comme suit:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="{{ url_for('static', filename='public/favicon.ico') }}" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="{{ url_for('static', filename='public/logo192.png') }}" />
<link rel="manifest" href="{{ url_for('static', filename='public/manifest.json') }}" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="{{ url_for('static', filename='compiled/bundles.js') }}?v={{ range(50)|random }}"></script>
</body>
</html>
PS: Vous pouvez avoir du mal à faire le bon rendu des images SVG
, c’est pourquoi je vous conseil de modifier le fichier src/index.js
et utiliser le tag SVG
via le paquet svg-inline-loader
comme suit:
import React from 'react';
import logo from './logo.svg';
import './App.css';
import SVG from 'react-inlinesvg';
function App() {
return (
<div className="App">
<header className="App-header">
<SVG src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Creattion d’une vue avec Flask:
app.py
from flask import Flask, render_template
from flask.views import MethodView
application = Flask(
__name__,
template_folder='frontend/',
static_folder='frontend/'
)
class IndexView(MethodView):
template_name = 'public/index.html'
def get(self):
return render_template(self.template_name)
application.add_url_rule('/', view_func=IndexView.as_view('index'))
wsgi.py
from app import application
if __name__ == '__main__':
DEBUG = True
PORT = 5000
HOST = '0.0.0.0'
application.run(host=HOST, port=PORT, debug=DEBUG)
Tout exécuter!
Pour exécuter ce tutoriel vous avez 3 modes avec NPM
et 2 modes avec Flask
.
Dans, le fichier packages.json
on a spécifié 3 modes qui sont:
- dev: Mode développent
- build: Mode Production
- watch: Mode développent avec le
live reload
des changements au niveau deReact
Et au niveay de Flask
, on a deux modes selon la valeur de la variable DEBUG
.
Ceci dit, en mode de développent pur on pourra lancer 2 terminales: Une terminale qui lance le mode watch
de l’app en React et l’autre lance le serveur de développent de Flask en mode DEBUG.
En gros:
# Première terminale
(venv)$> flask wsgi.py
# Deuxième terminale
(venv)$> cd frontend
(venv)$> npm run watch
Par contre en mode de Production
, ce qu’on a à faire c’est juste lancer:
(venv)$> npm build
Et ensuite servir notre application Flask
avec Gunicorn
ou autre en se servant du fichier React/JavaScript
compilé frontend/compiled/bundles.js
.
Commentaires