# 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 = os.path.join(app.static_folder, '') # path to the static file folder, with trailing slash hash_table = {} # map of file hashes app.logger.debug('Computing cache-busting values...') # compute file hashes for dirpath, __, 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: file_hash = hashlib.md5(f.read()).hexdigest()[:7] # save version to tables file_path = rooted_filename.replace(static_folder, "") file_path = file_path.replace("\\", "/") # Convert Windows path to web path hash_table[file_path] = file_hash 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": file_hash = bust_filename(values["filename"]) if file_hash: values["q"] = file_hash 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