Use cache busting for css/js files
On app init, short hashes are generated from file checksums to use for cache busting. These hashes are added into the full file name and used to symlink to the actual file contents. These symlinks are loaded in the jinja templates for each page, and can tell the browser to load a new file if the hash changes. This is only in place for css and js files, but can be extended in the future for other file types if needed.main
parent
c41e0fc239
commit
68fdd55482
|
@ -2,6 +2,7 @@ from app.filter import clean_query
|
|||
from app.request import send_tor_signal
|
||||
from app.utils.session import generate_user_key
|
||||
from app.utils.bangs import gen_bangs_json
|
||||
from app.utils.misc import gen_file_hash
|
||||
from flask import Flask
|
||||
from flask_session import Session
|
||||
import json
|
||||
|
@ -30,6 +31,9 @@ app.config['APP_ROOT'] = os.getenv(
|
|||
app.config['STATIC_FOLDER'] = os.getenv(
|
||||
'STATIC_FOLDER',
|
||||
os.path.join(app.config['APP_ROOT'], 'static'))
|
||||
app.config['BUILD_FOLDER'] = os.path.join(
|
||||
app.config['STATIC_FOLDER'], 'build')
|
||||
app.config['CACHE_BUSTING_MAP'] = {}
|
||||
app.config['LANGUAGES'] = json.load(open(
|
||||
os.path.join(app.config['STATIC_FOLDER'], 'settings/languages.json')))
|
||||
app.config['COUNTRIES'] = json.load(open(
|
||||
|
@ -73,9 +77,6 @@ app.config['CSP'] = 'default-src \'none\';' \
|
|||
'connect-src \'self\';' \
|
||||
'form-action \'self\';'
|
||||
|
||||
# Templating functions
|
||||
app.jinja_env.globals.update(clean_query=clean_query)
|
||||
|
||||
if not os.path.exists(app.config['CONFIG_PATH']):
|
||||
os.makedirs(app.config['CONFIG_PATH'])
|
||||
|
||||
|
@ -88,6 +89,31 @@ if not os.path.exists(app.config['BANG_PATH']):
|
|||
if not os.path.exists(app.config['BANG_FILE']):
|
||||
gen_bangs_json(app.config['BANG_FILE'])
|
||||
|
||||
# Build new mapping of static files for cache busting
|
||||
if not os.path.exists(app.config['BUILD_FOLDER']):
|
||||
os.makedirs(app.config['BUILD_FOLDER'])
|
||||
|
||||
cache_busting_dirs = ['css', 'js']
|
||||
for cb_dir in cache_busting_dirs:
|
||||
full_cb_dir = os.path.join(app.config['STATIC_FOLDER'], cb_dir)
|
||||
for cb_file in os.listdir(full_cb_dir):
|
||||
# Create hash from current file state
|
||||
full_cb_path = os.path.join(full_cb_dir, cb_file)
|
||||
cb_file_link = gen_file_hash(full_cb_dir, cb_file)
|
||||
build_path = os.path.join(app.config['BUILD_FOLDER'], cb_file_link)
|
||||
os.symlink(full_cb_path, build_path)
|
||||
|
||||
# Create mapping for relative path urls
|
||||
map_path = build_path.replace(app.config['APP_ROOT'], '')
|
||||
if map_path.startswith('/'):
|
||||
map_path = map_path[1:]
|
||||
app.config['CACHE_BUSTING_MAP'][cb_file] = map_path
|
||||
|
||||
# Templating functions
|
||||
app.jinja_env.globals.update(clean_query=clean_query)
|
||||
app.jinja_env.globals.update(
|
||||
cb_url=lambda f: app.config['CACHE_BUSTING_MAP'][f])
|
||||
|
||||
Session(app)
|
||||
|
||||
# Attempt to acquire tor identity, to determine if Tor config is available
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
@import "/static/css/light-theme.css" screen;
|
||||
@import "/static/css/dark-theme.css" screen and (prefers-color-scheme: dark);
|
|
@ -5,14 +5,21 @@
|
|||
<link rel="search" href="opensearch.xml" type="application/opensearchdescription+xml" title="Whoogle Search">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<link rel="stylesheet" href="static/css/input.css">
|
||||
<link rel="stylesheet" href="static/css/search.css">
|
||||
<link rel="stylesheet" href="static/css/variables.css">
|
||||
<link rel="stylesheet" href="static/css/header.css">
|
||||
{% if config.theme %}
|
||||
<link rel="stylesheet" href="static/css/{{ config.theme }}-theme.css"/>
|
||||
<link rel="stylesheet" href="{{ cb_url('input.css') }}">
|
||||
<link rel="stylesheet" href="{{ cb_url('search.css') }}">
|
||||
<link rel="stylesheet" href="{{ cb_url('variables.css') }}">
|
||||
<link rel="stylesheet" href="{{ cb_url('header.css') }}">
|
||||
{% if config.theme %}
|
||||
{% if config.theme == 'system' %}
|
||||
<style>
|
||||
@import "{{ cb_url('light-theme.css') }}" screen;
|
||||
@import "{{ cb_url('dark-theme.css') }}" screen and (prefers-color-scheme: dark);
|
||||
</style>
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="{{ cb_url(config.theme + '-theme.css') }}"/>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="static/css/{{ 'dark' if config.dark else 'light' }}-theme.css"/>
|
||||
<link rel="stylesheet" href="{{ cb_url(('dark' if config.dark else 'light') + '-theme.css') }}"/>
|
||||
{% endif %}
|
||||
<style>{{ config.style }}</style>
|
||||
<title>{{ clean_query(query) }} - Whoogle Search</title>
|
||||
|
@ -33,7 +40,7 @@
|
|||
<a id="gh-link" href="https://github.com/benbusby/whoogle-search">{{ translation['github-link'] }}</a>
|
||||
</p>
|
||||
</footer>
|
||||
<script src="static/js/autocomplete.js"></script>
|
||||
<script src="static/js/utils.js"></script>
|
||||
<script src="static/js/keyboard.js"></script>
|
||||
<script src="{{ cb_url('autocomplete.js') }}"></script>
|
||||
<script src="{{ cb_url('utils.js') }}"></script>
|
||||
<script src="{{ cb_url('keyboard.js') }}"></script>
|
||||
</html>
|
||||
|
|
|
@ -62,4 +62,4 @@
|
|||
</header>
|
||||
{% endif %}
|
||||
|
||||
<script type="text/javascript" src="static/js/header.js"></script>
|
||||
<script type="text/javascript" src="{{ cb_url('header.js') }}"></script>
|
||||
|
|
|
@ -17,17 +17,24 @@
|
|||
<meta name="referrer" content="no-referrer">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="msapplication-TileImage" content="static/img/favicon/ms-icon-144x144.png">
|
||||
<script type="text/javascript" src="static/js/autocomplete.js"></script>
|
||||
<script type="text/javascript" src="static/js/controller.js"></script>
|
||||
<script type="text/javascript" src="{{ cb_url('autocomplete.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ cb_url('controller.js') }}"></script>
|
||||
<link rel="search" href="opensearch.xml" type="application/opensearchdescription+xml" title="Whoogle Search">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="static/css/variables.css">
|
||||
<link rel="stylesheet" href="{{ cb_url('variables.css') }}">
|
||||
{% if config.theme %}
|
||||
<link rel="stylesheet" href="static/css/{{ config.theme }}-theme.css"/>
|
||||
{% if config.theme == 'system' %}
|
||||
<style>
|
||||
@import "{{ cb_url('light-theme.css') }}" screen;
|
||||
@import "{{ cb_url('dark-theme.css') }}" screen and (prefers-color-scheme: dark);
|
||||
</style>
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="{{ cb_url(config.theme + '-theme.css') }}"/>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="static/css/{{ 'dark' if config.dark else 'light' }}-theme.css"/>
|
||||
<link rel="stylesheet" href="{{ cb_url(('dark' if config.dark else 'light') + '-theme.css') }}"/>
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="static/css/main.css">
|
||||
<link rel="stylesheet" href="{{ cb_url('main.css') }}">
|
||||
<noscript>
|
||||
<style>
|
||||
#main { display: inherit !important; }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<link rel="stylesheet" href="static/css/logo.css">
|
||||
<link rel="stylesheet" href="{{ cb_url('logo.css') }}">
|
||||
<svg id="Layer_1" class="whoogle-svg" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1028 254">
|
||||
<defs>
|
||||
<style>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import hashlib
|
||||
import os
|
||||
|
||||
|
||||
def gen_file_hash(path: str, static_file: str) -> str:
|
||||
file_contents = open(os.path.join(path, static_file), 'rb').read()
|
||||
file_hash = hashlib.md5(file_contents).hexdigest()[:8]
|
||||
filename_split = os.path.splitext(static_file)
|
||||
|
||||
return filename_split[0] + '.' + file_hash + filename_split[-1]
|
Loading…
Reference in New Issue