Commit a27848b3 authored by Jonathan Rehm's avatar Jonathan Rehm

Add static asset cache busting

Calculates MD5 hash of static assets on server start. These are appended to the file name's when url_for is used, telling browsers to download the latest version of the files, e.g. style.css?q=81cf0ee.

Inspired by https://github.com/ChrisTM/Flask-CacheBust but uses query strings instead of rewriting the path because fonts inside CSS files break when the path is rewritten.
parent 08d0404e
# Inspired by https://github.com/ChrisTM/Flask-CacheBust
# Uses query strings so CSS font files are found without having to resort to absolute URLs
import hashlib
import os
def init_cache_busting(app):
"""
Configure `app` to so that `url_for` adds a unique query string to URLs generated
for the `'static'` endpoint.
This allows setting long cache expiration values on static resources
because whenever the resource changes, so does its URL.
"""
static_folder = app.static_folder # the rooted path to the static file folder
hash_table = {} # map of file hashes
app.logger.debug('Computing cache-busting values...')
# compute file hashes
for dirpath, dirnames, filenames in os.walk(static_folder):
for filename in filenames:
# compute version component
rooted_filename = os.path.join(dirpath, filename)
with open(rooted_filename, 'r') as f:
version = hashlib.md5(f.read()).hexdigest()[:7]
# save version to tables
file_path = rooted_filename.replace(static_folder + "/", "")
hash_table[file_path] = version
app.logger.debug('Finished computing cache-busting values')
def bust_filename(filename):
return hash_table.get(filename, "")
def unbust_filename(filename):
return filename.split("?", 1)[0]
@app.url_defaults
def reverse_to_cache_busted_url(endpoint, values):
"""
Make `url_for` produce busted filenames when using the 'static' endpoint.
"""
if endpoint == 'static':
values["q"] = bust_filename(values['filename'])
def debusting_static_view(filename):
"""
Serve a request for a static file having a busted name.
"""
return original_static_view(filename=unbust_filename(filename))
# Replace the default static file view with our debusting view.
original_static_view = app.view_functions['static']
app.view_functions['static'] = debusting_static_view
......@@ -21,6 +21,7 @@ from flask import (Flask, render_template, request, Response, redirect,
url_for, send_from_directory, make_response, g, flash,
abort, Markup, stream_with_context)
from flask import __version__ as flaskVersion
import cache_buster
import ub
from ub import config
import helper
......@@ -200,6 +201,7 @@ mimetypes.add_type('image/vnd.djvu', '.djvu')
app = (Flask(__name__))
app.wsgi_app = ReverseProxied(app.wsgi_app)
cache_buster.init_cache_busting(app)
gevent_server = None
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment