DEV Community

loading...

Vue+Flask on DigitalOcean: how to proceed?

Daniel da Rocha
architect turned dev
・1 min read

Hi!

Following my earlier post, I am now trying to have my app running on a single Digital Ocean droplet.

But how should I approach it?

Is it correct to have my Vue app being served to the outside world and the Flask API being served locally in the droplet, and have my Vue app access it via localhost:port?

Or do I need two server blocks, one for the Vue app and one for the Flask API?

(the API is for internal use only, I do not intend to have a public endpoint to it)

Thanks for the help!
Daniel

Discussion (6)

Collapse
rhymes profile image
rhymes

I don't know specifically about Digital Ocean but you should probably just serve the VueJS app from Flask's static app. Treat it as just a JS dependency that's served by the server.

How to do it (I'm using blueprints but you can do it with the regular app)

# Used to find the Vue.js frontend app
TEMPLATE_FOLDER = os.path.abspath(
    os.path.join(os.path.dirname(app.__file__), '../..', 'frontend/dist')
)
STATIC_FOLDER = os.path.join(TEMPLATE_FOLDER, 'static')

# look for the frontend index.html page, it's a Vue.js SPA
app = Blueprint(
    'frontend',
    'app.frontend',
    url_prefix='/',
    template_folder=TEMPLATE_FOLDER,
    static_folder=STATIC_FOLDER,
    static_url_path='/static'
)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def index(path):
    'Frontend application'
    return render_template('index.html')

This tells Flask to serve the result of yarn build (the static app) as regular js and css dependencies. The frontend in my case sits in the same repository, that's why this works.

These two lines:

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')

make sure that all paths get redirected to the SPA so that it's going to be Vue's router responsibility to handle them.

On the Vue part this is the configuration (I'm using vue cli 3 but it worked with the old vue template in a similar way):

module.exports = {
  assetsDir: 'static'
}

so that the build command will put the static files in a static subdirectory to make Flask happy :-)

Collapse
danroc profile image
Daniel da Rocha Author

Wow, would never have thought about doing it this way.
Sounds great. And that makes all my API calls quite simple.
Will give it a try.

Thanks!

Collapse
colinmtech profile image
Colin Morgan

I deployed a side project using Flask/React last week on digital ocean. I just installed nginx and configured a block to serve a static build of the react app and one to serve the flask API via gunicorn. I also setup gitlab CI to build/deploy, which seems to be working pretty good so far.

If your API is being used by the Vue app, it'll need to be public because of the nature of SPAs. You could probably enforce domain referral requirements, but usually you just secure the API with the knowledge that it's publicly available.

Collapse
danroc profile image
Daniel da Rocha Author

If your API is being used by the Vue app, it'll need to be public because of the nature of SPAs.

But that only in this solution or also in @rhymes solution described above?

Collapse
rhymes profile image
rhymes

@danroc mine is behind basic authentication. The SPA talks to the API and they both are behind basic authentication (TLS only)

Collapse
colinmtech profile image
Colin Morgan

It'll be public in his solution, as well. The only difference is that the initial index.html file will be served via the flask app, instead of just through nginx.