Simple SPA setup with Vue CLI 3 and Flask

Things move quickly on the web, and it's not always easy to find the most recent and best way to set up a project. Here's my quick and easy setup for making a single page application with Flask and Vue.

Flask setup

Set up a virtualenv and install Flask. I recommend looking into Pipenv to track and handle Python dependencies in a better way, but let's keep thing simple and use a local virtualenv for the project for now:

$ mkdir my-project
$ virtualenv venv -p python3
$ . env/bin/activate
$ pip install flask

Now add a file called app.py. This is the default file the flask command will look for when launching the development server. In app.py, add:

from flask import Flask, render_template, jsonify

# Set up automatic serving of static Vue & frontend files and template folder for index.html.
app = Flask(__name__, static_folder='client/dist/static', template_folder='client/dist')


# Add your routes here:
@app.route('/api/posts')
def blog_posts():
    return jsonify([])


# Make a "catch all route" so all requests match our index.html file. This lets us use the new history APIs in the browser.
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def index(path):
    return render_template('index.html')

Now your Flask project is ready to serve requests. Try launching the Flask development server and make sure it works. Run:

$ export FLASK_ENV=development flask run

Go to localhost:5000/api/posts and check that an empty JSON list is returned.

Vue setup

Install Vue CLI 3 globally:

$ npm install @vue/cli -g

Start a new Vue project using:

$ vue create client

You will be asked a few configuration questions. Make sure you install "Router" and choose whatever else you want. When the setup is completed, navigate to the client directory and create a file called vue.config.js. In this file, put:

module.exports = {
    assetsDir: 'static', // For simple configuration of static files in Flask (the "static_folder='client/dist/static'" part in app.py)
    devServer: {
        proxy: 'http://localhost:5000' // So that the client dev server can access your Flask routes
    }
};

Great, setup finished!

Developing and building for production

Open two terminal windows / tabs, and start both the Flask development server (if it isn't already running from earlier), and the Vue / Webpack development server, like this:

# Terminal 1
$ export FLASK_ENV=development flask run # Might already be running from earlier

# Terminal 2
$ npm run serve

Open localhost:8080 in your browser. From the Vue app, any request you make that doesn't match any static files, will be proxied to your Flask app. No need to deal with CORS headers or any additional configuration.

When you want to build your frontend for production, simply run:

npm run build

Because we configured assetDir to be 'static', the production client side files will be put in a directory that's served from Flask, and the production build should be accessible from localhost:5000.