Use Vue. js and Flask to build a single-page App example, vue. jsflask
In this tutorial, we will explain how to connect a single-page vue. js application to the Flask backend.
In general, if you just want to use the vue. js library through the Flask template, there is no problem. However, it is actually a very obvious problem that Jinja (template engine) and Vue. js uses double braces for rendering, but it is only a fairly smooth solution.
I want a different example. If I need to create a single-page application (the application uses a single page,Vue-routerIn HTML5's History-mode and other useful functions) using vue. js, is Web service provided by Flask? To put it simply, it should be as follows:
Flask isIndex.htmlService,Index.htmlInclude my vue. js App.
In front-end development, I use Webpack, which provides all the cool functions.
Flask has APIs that I can access from my SPA.
I can access the API, even when I run Node. js for front-end development.
Does it sound interesting? Let's do this.
Complete source code, you can find here: https://github.com/oleg-agapov/flask-vue-spa
Client
I will use Vue CLI to generate the basic vue. js App. If you have not installed it, run:
$ npm install -g vue-cli
The client and backend code are split into different folders. Initialize the front-end running tracking:
$ mkdir flaskvue$ cd flaskvue$ vue init webpack frontend
Use the installation wizard. My settings are:
Vue is built only at runtime.
Install Vue-router.
Use ESLint to check the code.
Select an ESLint standard preset.
Do not try Karma + Mocha for unit testing.
End-to-end tests are not created using the nginx watch.
OK, then:
$ cd frontend$ npm install# after installation$ npm run dev
You can start the installation.Vue. jsApplication. Let's start by adding some pages.
AddHome. vueAndAbout. vueToFrontend/src/componentsFolder. They are very simple, like this:
// Home.vue<template><div><p>Home page</p></div></template>
And
// About.vue<template><div><p>About</p></div></template>
We will use them to correctly identify our current location (based on the address bar ). Now we need to changeFrontend/src/router/index. jsFile to use our new components:
import Vue from 'vue'import Router from 'vue-router'const routerOptions = [{ path: '/', component: 'Home' },{ path: '/about', component: 'About' }]const routes = routerOptions.map(route => {return {...route,component: () => import(`@/components/${route.component}.vue`)}})Vue.use(Router)export default new Router({routes,mode: 'history'})
If you try to enterLocalhost: 8080AndLocalhost: 8080/about, You should see the corresponding page.
We are almost ready to build a project and be able to create a static resource package. Before that, let's redefine the output directory for them. InFrontend/config/index. jsFind the next setting:
index: path.resolve(__dirname, '../dist/index.html'),assetsRoot: path.resolve(__dirname, '../dist'),
Change them
index: path.resolve(__dirname, '../../dist/index.html'),assetsRoot: path.resolve(__dirname, '../../dist'),
Therefore, HTML, CSS, and JS in the/dist folder are in the same level directory/frontend. Now you can run$ Npm run buildCreate a package.
Backend
For the Flask server, I will use Python 3.6. In/FlaskvueCreate a new sub-folder to store the backend code and initialize the virtual environment:
$ mkdir backend$ cd backend$ virtualenv -p python3 venv
To make the virtual environment run (MacOS ):
$ source venv/bin/activate
This document (http://pymote.readthedocs.io/en/latest/install/windows_virtualenv.html) needs to be activated in Windows ).
Install in a virtual environment:
(venv) pip install Flask
Now let's write code for the Flask server. Create the root directory file run. py:
(venv) cd ..(venv) touch run.py
Add the following code to this file:
from flask import Flask, render_templateapp = Flask(__name__,static_folder = "./dist/static",template_folder = "./dist")@app.route('/')def index():return render_template("index.html")
This code is slightly different from the ** Hello World ** code of Flask. The main difference is that we specify to store static files and templates in folders./DistTo distinguish it from our front-end folder. Run Flask server in the root folder:
(venv) FLASK_APP=run.py FLASK_DEBUG=1 flask run
This will start the Web server on the local host:Localhost: 5000OnFLASK_APPServer startup file,Flask_debug = 1It will run in debug mode. If everything is correct, you will see that you are familiar with the home page and have completed Vue settings.
At the same time, if you try to enter the/about page, you will face an error. Flask throws an error saying that the requested URL cannot be found. For example, we used html5's history-modeto configure the redirection of the web server in vue-router.pdf and directed all the mappings to index.html. It is easy to use Flask. Modify the existing route to the following:
@app.route('/', defaults={'path': ''})@app.route('/<path:path>')def catch_all(path):return render_template("index.html")
Enter the URL localhost: 5000/about to redirect to index.html and vue-router to process the route.
Add 404 page
Partition (or even non-existent page ). Therefore, we need to process unknown paths in the vue. js application. Of course, all work can be done in our Routing File.
Add the following line to frontend/src/router/index. js:
const routerOptions = [{ path: '/', component: 'Home' },{ path: '/about', component: 'About' },{ path: '*', component: 'NotFound' }]
The path '*' Here is a wildcard,Vue-routerYou will know all the other paths except the ones defined above. Now we need more CreationsNotFound. vueThe file is in the **/components ** directory. It's easy to try:
// NotFound.vue<template><div><p>404 - Not Found</p></div></template>
The running front-end server is running againNpm run dev, Try to enter some meaningless addresses such:Localhost: 8080/gljhewrgoh. You should see our "not found" message.
Add API
OurVue. js/flaskThe last example of this tutorial is the server-side API creation and scheduling client. We will create a simple Api that will return a random number from 1 to 100.
Open run. py and add:
from flask import Flask, render_template, jsonifyfrom random import *app = Flask(__name__,static_folder = "./dist/static",template_folder = "./dist")@app.route('/api/random')def random_number():response = {'randomNumber': randint(1, 100)}return jsonify(response)@app.route('/', defaults={'path': ''})@app.route('/<path:path>')def catch_all(path):return render_template("index.html")
First, I import the random library and the jsonify function from the Flask library. Then I added a new route/Api/randomTo return a JSON file like this:
{"randomNumber": 36}
You can test the path through local browsing:Localhost: 5000/api/random.
At this time, the work on the server has been completed. It is displayed on the client. Let's change the home. vue component to display the random number:
<template><div><p>Home page</p><p>Random number from backend: {{ randomNumber }}</p><button @click="getRandom">New random number</button></div></template><script>export default {data () {return {randomNumber: 0}},methods: {getRandomInt (min, max) {min = Math.ceil(min)max = Math.floor(max)return Math.floor(Math.random() * (max - min + 1)) + min},getRandom () {this.randomNumber = this.getRandomInt(1, 100)}},created () {this.getRandom()}}</script>
At this stage, we only imitate the random number generation process of the client. Therefore, this component works like this:
- When initializing a variableRandomNumberEqual to 0.
- In the methods section, we use the getRandomInt (min, max) function to return a random number from a specified range,GetrandomThe function generates a random number and assigns it to randomNumber.
- Component MethodGetrandomAfter creation, the system will be called to initialize random numbers.
- In the Click Event of the button, we will useGetrandomMethod to obtain a new random number
Now on the homepage, you should see the random number that we generated in the front-end. Let's connect it to the backend.
For this purpose, I will useAxiosLibrary. It allows us to respond to HTTP requests and useJsonReturnJavaScript Promise. We will install it:
(venv) cd frontend(venv) npm install --save axios
OpenHome. vueIn<Script>Add some changes:
import axios from 'axios'methods: {getRandom () {// this.randomNumber = this.getRandomInt(1, 100)this.randomNumber = this.getRandomFromBackend()},getRandomFromBackend () {const path = `http://localhost:5000/api/random`axios.get(path).then(response => {this.randomNumber = response.data.randomNumber}).catch(error => {console.log(error)})}}
At the top, we need to reference the Axios library. Then there is a new methodGetrandomfrombackendThe API and retrieval results will be called asynchronously using Axios. Finally,GetrandomThe method should be used nowGetrandomfrombackendThe function returns a random value.
Save the file, go to the browser, and run a development server to refresh it again.Localhost: 8080. You should see that there is no random value for console errors. But don't worry. Everything works. We getCORSThe error means that the Flask Server API will shut down other Web servers by default (here, the vue. js App is an application running on the Node. js server ). If youNpm run buildProjectLocalhost: 5000(For example, Flask server) you will see that the App is working. However, it is not convenient to create a package every time you make some changes to the client application.
We can use the Flask package of the CORS plug-in to create an API access rule. The plug-in is called FlaskCORS. Let's install it:
(venv) pip install -U flask-cors
You can read the document to better explain how to use CORS on your server. I will use a specific method and set ** {"origins ": "*"} ** applies to all/api/* routes (so that everyone can use my API ). Add:
from flask_cors import CORSapp = Flask(__name__,static_folder = "./dist/static",template_folder = "./dist")cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
With this change, you can call the server from the front-end.
Update:
In fact, CORS is not required if you want to use Flask to provide static files. Thanks to Carson Gee for the following moves.
This is the idea. If the application is in debug mode, it will only act as a proxy for our front-end servers. Otherwise (in production), it only serves static files. So we do this:
import requests@app.route('/', defaults={'path': ''})@app.route('/<path:path>')def catch_all(path):if app.debug:return requests.get('http://localhost:8080/{}'.format(path)).textreturn render_template("index.html")
Elegant magic: sparkles :!
Now we have a complete full stack ** (full-stack)Applications, with your favoriteVue. jsAndFlask ** technology build.
Postscript
Finally, I would like to talk a few words about how to improve this solution.
First, use CORS if you want your API to access external servers. Otherwise, you only need to use the proxy server and front-end development skills.
Another improvement is to avoid hard-coded API routing on the client. You may need to consider the dictionary of some API endpoints. Therefore, when you change the API route, you only need to refresh a dictionary. The front end still has a valid endpoint.
Generally, during development, you have at least two terminal windows: Flask and vue. js. In production, you can get rid of Vue and only run the Node. js server separately.
Source code: https://github.com/oleg-agapov/flask-vue-spa
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.