In this tutorial we will show you how to connect vue.js single page applications to the Flask backend.

In general, it’s fine if you just want to use the vue.js library via the Flask template. However, there is an obvious problem that Jinja (the template engine) also uses double curly braces for rendering like vue.js, but this is a half-assed solution.

I want a different example. What if I need to build a single page application (the application uses a single page, vue-router in HTML5’s history-mode and many more nice features) with vue.js, served by Flask? In a nutshell, it should look like this:

Flask serves for index.html, which contains my vue.js App.

I use Webpack for front-end development and it provides all the cool features.

Flask has an API side that I can access from my SPA.

I can access the API side, even when I’m running Node.js for front-end development.

Does that sound like fun? So let’s do it this way.

The full source code, which you can find here:

https://github.com/oleg-agapov/flask-vue-spa

The client

I will use the Vue CLI to generate the basic vue.js App. If you haven’t already installed it, run:

$ npm install -g vue-cli
Copy the code

The client and back-end code will be split into different folders. Initialize the front-end part of the run trace:

$ mkdir flaskvue
$ cd flaskvue
$ vue init webpack frontend
Copy the code

Through the Installation wizard. My Settings are:

  1. Vue is only built at run time.

  2. Install the Vue – the router.

  3. Use ESLint to check code.

  4. Select an ESLint standard preset.

  5. Do not try Karma + Mocha for unit testing.

  6. Build end-to-end testing without Using Nightwatch.

Ok, here we go:

$ cd frontend
$ npm install
# after installation
$ npm run dev
Copy the code

Now you can start installing the vue.js application. Let’s start by adding some pages.

Add home.vue and about.vue to the frontend/ SRC/Components folder. They’re very simple, like this:

// Home.vue

<template>
<div>
<p>Home page</p>
</div>
</template>
Copy the code

and

// About.vue

<template>
<div>
<p>About</p>
</div>
</template>
Copy the code

We will use them to correctly identify our current location (according to the address bar). Now we need to change the frontend/SRC/router/index. The js file 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'
})
Copy the code

If you try to type localhost:8080 and localhost:8080/about, you should see the corresponding page.

We are almost ready to build a project and can create a static resource file package. Before we do that, let’s redefine the output directory for them. Find the next setting in frontend/config/index.js:

index: path.resolve(__dirname, '.. /dist/index.html'),
assetsRoot: path.resolve(__dirname, '.. /dist'),
Copy the code

Change them to

index: path.resolve(__dirname, '.. /.. /dist/index.html'),
assetsRoot: path.resolve(__dirname, '.. /.. /dist'),
Copy the code

Therefore, the HTML, CSS, and JS of /dist will be in the same level as /frontend. Now you can run $NPM run build to create a package.

The back-end

For the Flask server, I will use Python version 3.6. Create a new subfolder in/flaskVue to hold backend code and initialize the virtual environment:

$ mkdir backend
$ cd backend
$ virtualenv -p python3 venv
Copy the code

To run in a virtual environment (MacOS) :

$ source venv/bin/activate
Copy the code

In Windows need to activate the document (http://pymote.readthedocs.io/en/latest/install/windows_virtualenv.html).

Install in virtual environment:

(venv) pip install Flask
Copy the code

Now let’s write the code for the Flask server. Create the root directory file run.py:

(venv) cd. (venv) touch run.pyCopy the code

Add the next code to this file:

from flask import Flask, render_template
app = Flask(__name__,
static_folder = "./dist/static",
template_folder = "./dist")

@app.route('/')
def index():
return render_template("index.html")
Copy the code

This code is slightly different from Flask’s ** “Hello World” ** code. The main difference is that we specify the location to store static files and templates in folder /dist to distinguish it from our front-end folder. Run the Flask server in the root folder:

(venv) FLASK_APP=run.py FLASK_DEBUG=1 flask run
Copy the code

This will start the FLASK_APP server side startup file on the localhost Web server: localhost:5000 and flask_DEBUG = 1 will run in debug mode. If everything is correct, you will see the familiar home page and you have finished setting up the Vue.

Also, if you try to enter the /about page, you will face an error. Flask throws an error saying that the requested URL was not found. In fact, since we are using HTML5 history-mode on vue-router, we need to configure the Web server to redirect all paths to index.html. It’s easy to do in a 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")
Copy the code

Now entering the url localhost:5000/about will redirect to index.html and vue-router will handle the route.

Add 404

Since we have an all-encompassing path, our Web server is having a hard time catching 404 errors these days, and Flask directs all requests to index.html (pages that don’t even exist). So we need to deal with unknown paths in vue.js application. Of course, all the work can be done in our routing file.

In the frontend/SRC/router/index. Js to add the next line:

const routerOptions = [
{ path: '/', component: 'Home' },
{ path: '/about', component: 'About' },
{ path: The '*', component: 'NotFound'}]Copy the code

Where the path ‘*’ is a wildcard, vue-router knows any path other than the one we defined above. Now we need to create more NotFound. Vue files in the **/components** directory. It’s easy to try:

// NotFound.vue

<template>
<div>
<p>404 - Not Found</p>
</div>
</template>
Copy the code

Now run the front-end server NPM again run dev, try entering some meaningless address such as: localhost: 8080 / gljhewrgoh. You should see our “not found” message.

Add the API side

The final example of our vue.js/flask tutorial will be server-side API creation and scheduling of clients. 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, jsonify
from 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")
Copy the code

First I import the Random library and jsonify functions from the Flask library. Then I added a new route/API /random to return JSON like this:

{
"randomNumber": 36}Copy the code

You can browse, by local test this path: localhost: 5000 / API/random.

At this point, the server is complete. It’s time to display it on the client side. Let’s change the home.vue component to display random numbers:

<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>
Copy the code

At this stage, we just mimic the random number generation process on the client side. So, here’s how this component works:

  1. At initialization the variable randomNumber equals 0.
  2. In the methods section, we use the getRandomInt(min, Max) function to return a randomNumber from the specified range. The getrandom function will generate the randomNumber and assign the value to randomNumber
  3. Once created, the component method getrandom will be called to initialize the random number
  4. In the button click event we will use the Getrandom method to get a new random number

Now on the home page, you should see the front end showing the random numbers we generated. Let’s connect it to the back end.

I’ll use the AXIos library for this purpose. It allows us to respond to HTTP requests and return JavaScript promises with Json. Let’s install it:

(venv) cd frontend
(venv) npm install --save axios
Copy the code

Open home.vue and add some changes to the

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

}

}
Copy the code

At the top, we need to reference the Axios library. Then a new method, GetrandomFromBackend, uses Axios to asynchronously invoke the API and retrieve the results. Finally, the Getrandom method should now use the GetrandomFromBackend function to get a random value.

Save the file, go to the browser, run a development server and refresh localhost:8080 again. You should see console errors with no random values. But don’t worry, everything’s fine. The error we got with CORS means that the Flask server API shuts down other Web servers by default (in our case, vue.js App is an application running on node.js server). If you NPM run build projects, you will see the App working in localHost :5000 (e.g. Flask server). However, it is not very convenient to create a package every time some change is made to the client application.

Let’s use the Flask with the CORS plug-in packaged, which will enable us to create an API access rule. The plugin is called FlaskCORS, let’s install it:

(venv) pip install -U flask-cors
Copy the code

You can read the documentation to better explain how you want your server to use CORS. I’ll use a specific method and apply **{” origins “:” * “}** to all/API /* routes (so everyone can use my API side). Add to run.py:

from flask_cors import CORS
app = Flask(__name__,
static_folder = "./dist/static",
template_folder = "./dist")
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
Copy the code

With this change, you can call the server side from the front end.

Update:

In fact, you don’t need CORS if you want to serve static files through Flask. Thanks to Carson Gee for this next move.

Here’s the idea. If the application is in debug mode, it will only represent our front-end server. Otherwise (in production) only static files are served. So here’s what we do:

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)).text

return render_template("index.html")
Copy the code

Very elegant magic ✨!

You now have a complete full-stack application, built using your favorite vue.js and Flask** techniques.

Afterword.

Finally, I want to say a few words about how to improve the solution.

Use CORS first if you want your API side to access external servers. Otherwise, you just need to use proxy servers and front-end development techniques.

Another improvement is to avoid client hard-coding API routing. Perhaps you need to consider a dictionary of API endpoints. Therefore, when you change API routing, you only need to refresh a dictionary. The front end still has a valid endpoint.

Usually during development you will have at least 2 terminal Windows: one is Flask and another is vue.js. You can get rid of Vue in production and just run node.js server alone.

Source code: https://github.com/oleg-agapov/flask-vue-spa

Thanks for reading!

Collect wisdom net (www.hubwiz.com) small wisdom original translation!!

Share a tutorial on vue.js 2’s entry-level Family bucket series:

  1. Vue. Js 2 entry and improve: xc.hubwiz.com/course/vue….
  2. Vuex 2 entry and improve: xc.hubwiz.com/course/vuex
  3. Vue – the router 2 entry and improve: xc.hubwiz.com/course/vuer…
  4. Vue. Js 2 engineering practice: xc.hubwiz.com/course/vueg…

Flask tutorial is recommended for you:

A simple flask http://xc.hubwiz.com/course/562427361bc20c980538e26f