From fcb51c09d3b97150a908b624890799ddbf34fc43 Mon Sep 17 00:00:00 2001 From: TLSM Date: Tue, 30 Aug 2022 16:00:24 -0400 Subject: [PATCH] Implement assetcache module with asset hashing. Provides a module `assetcache` to support automatic cachebusting of static web assets, rather than the current approach of incrementing a version number. On module load, it walks the file/assets/ dir, computes a CRC32 of each asset, and provides those hashes via `assetcache_get(path)` at runtime. The primary consumer of hashes at present is the new `asset` filter for Jinja2, which accepts a relative asset path and returns the full path, with cache busting, suitable for final use in the template. Ex: `{{ 'css/main.css' | asset }}` --- files/helpers/assetcache.py | 20 ++++++++++++++++++++ files/helpers/jinja2.py | 10 ++++++++++ 2 files changed, 30 insertions(+) create mode 100644 files/helpers/assetcache.py diff --git a/files/helpers/assetcache.py b/files/helpers/assetcache.py new file mode 100644 index 000000000..fa85ba8aa --- /dev/null +++ b/files/helpers/assetcache.py @@ -0,0 +1,20 @@ +import os +import zlib +from collections import defaultdict + +ASSET_DIR = 'files/assets' +ASSET_CACHE = defaultdict(lambda: None) + +def assetcache_build(asset_dir): + for root, dirs, files in os.walk(asset_dir): + for fname in files: + fpath = root + '/' + fname + relpath = fpath[len(asset_dir) + 1:].replace('\\', '/') + with open(fpath, 'rb') as f: + fhash = zlib.crc32(f.read()) + ASSET_CACHE[relpath] = '%x' % fhash + +def assetcache_get(path): + return ASSET_CACHE[path] + +assetcache_build(ASSET_DIR) diff --git a/files/helpers/jinja2.py b/files/helpers/jinja2.py index a0dcddd18..0d9df2a58 100644 --- a/files/helpers/jinja2.py +++ b/files/helpers/jinja2.py @@ -3,6 +3,7 @@ from .get import * from os import listdir, environ from .const import * import time +from files.helpers.assetcache import assetcache_get @app.template_filter("post_embed") def post_embed(id, v): @@ -46,6 +47,15 @@ def timestamp(timestamp): years = int(months / 12) return f"{years}yr ago" +@app.template_filter("asset") +def template_asset(asset_path): + outpath = '/assets/' + asset_path + + cachehash = assetcache_get(asset_path) + if cachehash: + outpath += '?v=' + cachehash + + return outpath @app.context_processor def inject_constants():