Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serve static files from a CDN rather than Flask in production

In my Flask app I serve the static assets through the app in the dev env, but I'd like to use a CDN in production. Every asset is loaded in a template called base.html, so I guess the easiest solution is to pass a variable to the render function and use it in the template like:

<script src="{{ STATIC_URL }}/js/main.js"></script>

Normally it would be an empty string in the dev env, and the cdn url in production. I'd like to avoid passing this STATIC_URL variable to every view. I could make it work with

@bp.context_processor
def set_static_path():
    return dict(STATIC_URL='https://foo.bar.com')

But for me this seems a little hacky. Is there a better way to solve this problem?

like image 842
fodma1 Avatar asked Mar 06 '16 07:03

fodma1


1 Answers

There's no need to change how you link to static files, you can still use url_for('static', filename='myfile.txt'). Replace the default static view with one that redirects to the CDN if it is configured.

from urllib.parse import urljoin
# or for python 2: from urlparse import urljoin
from flask import redirect

@app.endpoint('static')
def static(filename):
    static_url = app.config.get('STATIC_URL')

    if static_url:
        return redirect(urljoin(static_url, filename))

    return app.send_static_file(filename)

Whether you're on a dev machine or production, set the STATIC_URL config value to the CDN and requests for static files will be redirected there.


Redirects are relatively cheap, and are remembered by browsers. If you get to the point where performance is meaningfully affected by them, you can write a function that links directly when using the CDN.

@app.template_global()
def static_url(filename):
    static_url = app.config.get('STATIC_URL')

    if static_url:
        return urljoin(static_url, filename)

    return url_for('static', filename=filename)

The template_global decorator makes the function available in all templates. Use it instead of url_for when you need urls for static files.


There may be a Flask extension that does this for you already. For example, Flask-S3 provides a url_for that serves static files from AWS S3.

like image 71
davidism Avatar answered Oct 02 '22 10:10

davidism