useFlask() useFlask() useFlask() useFlask() or how to use a - - PowerPoint PPT Presentation

useflask useflask useflask useflask
SMART_READER_LITE
LIVE PREVIEW

useFlask() useFlask() useFlask() useFlask() or how to use a - - PowerPoint PPT Presentation

useFlask() useFlask() useFlask() useFlask() or how to use a React frontend for your Flask app ABOUT ME ABOUT ME Adrian Mnnich @ThiefMaster Lead Developer of the Indico project at CERN One of the Pallets maintainers


slide-1
SLIDE 1

useFlask() useFlask()

slide-2
SLIDE 2

useFlask() useFlask()

…or how to use a React frontend for your Flask app

slide-3
SLIDE 3

ABOUT ME ABOUT ME

Adrian Mönnich @ThiefMaster

Lead Developer of the at CERN 🛡 One of the maintainers 🐎 Python enthusiast since almost 10 years ✨ Moved on from jQuery to React Indico project Pallets

slide-4
SLIDE 4

STATUS QUO STATUS QUO

Based on what people ask questions about on IRC WTForms jQuery AJAX JavaScript

slide-5
SLIDE 5

WTFORMS WTFORMS

Easy for simple cases 🎊

slide-6
SLIDE 6

WTFORMS WTFORMS

Easy for simple cases 🎊 Complex custom widgets? Welcome to WTF-Forms 🐓 Value round-trip even if validation fails! Garbage-in, garbage-out? 🗒

slide-7
SLIDE 7

JQUERY JQUERY

Do YOU still want to use it? 😝

slide-8
SLIDE 8

JQUERY JQUERY

Do YOU still want to use it? 😝 Spaghetti code Classes/IDs all over the code Barely maintainable

slide-9
SLIDE 9

AJAX AJAX

XMLHttpRequest API is horrible fetch() isn't bad Are you sending back large chunks of HTML? Duplicating code for your API?

slide-10
SLIDE 10

JAVASCRIPT JAVASCRIPT

Rarely transpiled (sometimes minified) Code written for old browsers  Why are you still writing the same kind of JS you wrote 10 years ago?

slide-11
SLIDE 11

HOW TO IMPROVE IT? HOW TO IMPROVE IT?

Build asset bundle with Webpack Use modern JavaScript (ES6+, ES201x) ✨ Make the frontend reactive

slide-12
SLIDE 12

No, it's not. Unless you do weird things.

Been there, done that.

But it is boilerplate code. "Configuring webpack is too hard"

slide-13
SLIDE 13

Can't we do something like… from webpack import config

slide-14
SLIDE 14

Almost! It's called create-react-app

Create React App is an officially supported way to create single-page React applications. It offers a modern build setup with no configuration.

slide-15
SLIDE 15

CREATE-REACT-APP CREATE-REACT-APP

Contains the whole build config Auto-rebuild 🏘 & hot reload 🔦 Includes its own dev server

slide-16
SLIDE 16

LET'S CODE! LET'S CODE!

slide-17
SLIDE 17

OUR FLASK APP OUR FLASK APP

app = Flask(__name__) @app.route('/api/time') def time(): return jsonify(now=datetime.now().isoformat()) @app.route('/api/greet/<name>') @app.route('/api/greet-stranger/', defaults={'name': 'mysterious person'}) def greeting(name): msg = 'Welcome, ' + name return jsonify(greeting=msg)

slide-18
SLIDE 18

GENERATE THE CLIENT GENERATE THE CLIENT

$ npx create-react-app client Creating a new React app in …/ep2019-flask-react/testapp/client. Installing packages. This might take a couple of minutes. Installing react, react-dom, and react-scripts... … We suggest that you begin by typing: cd client npm start Happy hacking!

slide-19
SLIDE 19

EXPORT ROUTES TO JS EXPORT ROUTES TO JS

Hardcoded URLs are ugly! 👏 Especially if they are dynamic 😡

slide-20
SLIDE 20

📧 Install some more packages

$ pip install flask-url-map-serializer $ npm install --save-dev flask-urls.macro $ npm install --save flask-urls

slide-21
SLIDE 21

🎤 Hook up the build scripts with Flask

// client/.babel-plugin-macrosrc.js const {execSync} = require('child_process'); const urlMap = JSON.parse(execSync('flask url_map_to_json')); module.exports = { flaskURLs: { urlMap } };

slide-22
SLIDE 22

🔘 Link the dev servers

// client/src/setupProxy.js const proxy = require('http-proxy-middleware'); module.exports = app => { app.use(proxy('/api', { target: process.env.FLASK_URL || 'http://127.0.0.1:5000' })); };

slide-23
SLIDE 23

RECAP RECAP

We now have: Our Flask app providing an API Boilerplate for a React frontend The ability to build Flask URLs in JS The CRA dev server forwarding /api/* to Flask

slide-24
SLIDE 24

// client/src/App.js import Demo from './Demo'; <Demo /> 1 // … 2 3 4 function App() { 5 return ( 6 {/* … */} 7 <header classname="App-header"> 8 <img src={logo} className="App-logo" alt="logo" /> 9 10 </header> 11 {/* … */} 12 ); 13 } 14

slide-25
SLIDE 25

// client/src/Demo.js import flask from 'flask-urls.macro'; const timeURL = flask`time`; const greetingURL = flask`greeting`; 1 import React, {useState, useEffect} from 'react'; 2 3 4 5 6 7 export default function Demo() { 8 // continued on next slide… 9 } 10

slide-26
SLIDE 26

const [time, setTime] = useState(null); useEffect(() => { (async () => { const resp = await fetch(timeURL()); const data = await resp.json(); setTime(data.now); })(); }, []); const url = greetingURL({name: 'snake'}); return time && ( <p>It's {time} and your greeting URL is {url}</p> ); 1 2 3 4 5 6 7 8 9 10 11 12 13

slide-27
SLIDE 27

How the hell does this all work?!

slide-28
SLIDE 28

How the hell does this all work?!

slide-29
SLIDE 29

How the hell does this all work?!

// Babel macro - runs at build time! import flask from 'flask-urls.macro'; // Tagged template compiles to function const greetingURL = flask`greeting`; // equivalent of url_for('greeting', name='snake') const url = greetingURL({name: 'snake'});

slide-30
SLIDE 30

How the hell does this all work?!

// Babel macro - runs at build time! import flask from 'flask-urls.macro'; // Tagged template compiles to function const greetingURL = flask`greeting`; // equivalent of url_for('greeting', name='snake') const url = greetingURL({name: 'snake'});

slide-31
SLIDE 31

How the hell does this all work?!

// Babel macro - runs at build time! import flask from 'flask-urls.macro'; // Tagged template compiles to function const greetingURL = flask`greeting`; // equivalent of url_for('greeting', name='snake') const url = greetingURL({name: 'snake'});

slide-32
SLIDE 32

That's the code generated by the macro

const greetingURL = flask_urls__WEBPACK_IMPORTED_MODULE_1___default.a.bind( null, { endpoint: "greeting", rules: [/* …building rules omitted here… */] }, "" );

slide-33
SLIDE 33

YOU CAN CONTRIBUTE! YOU CAN CONTRIBUTE!

We could really use… 🧿 Docs (only examples right now 😟) ✨ TypeScript stubs

🖦 More projects using it (and finding bugs? 🐜)

➡ Brag about having contributed to a CERN project! 🎊 indico/js-flask-urls

slide-34
SLIDE 34

OTHER COOL STUFF OTHER COOL STUFF

slide-35
SLIDE 35

Non-macro Babel plugin for Flask URL building Same features as the macro version Alternative to the macro, but requires control

  • ver the Webpack/Babel config

import greetingURL from 'flask-url:greeting'; import otherURL from 'flask-url:blueprint.endpoint';

slide-36
SLIDE 36

Server-side validation: Form handling & validation: webargs 🏂 react-final-form

slide-37
SLIDE 37

More complete example of React-Flask integration

Also covers how to build for production ThiefMaster/flask-cra-example

slide-38
SLIDE 38

FIND ME ON… FIND ME ON…

  @ThiefMaster

ThiefMaster @ Freenode (#pocoo, #indico)

slide-39
SLIDE 39

FIND ME ON… FIND ME ON…

  @ThiefMaster

ThiefMaster @ Freenode (#pocoo, #indico) …or right here! 🐎 I have hexagonal stickers!

…and my team at CERN is looking for a student intern!