[FEAT] add cache busting via static_url_for and settings.cache_version (#1964)

closes #1954
this PR add cache busting to `/static`
additionally i combined `lnbits/core/static` with `lnbits/static`, it was not necessary and added a lot of duplicate code for cache busting. now you have to include all static files inside the html files with `{{ static_url_for("static", "app.css" ) }}`

Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com>
Co-authored-by: Pavol Rusnak <pavol@rusnak.io>
This commit is contained in:
dni ⚡ 2023-10-27 13:50:49 +02:00 committed by GitHub
parent fed2d41139
commit 4d1c4f6348
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 122 additions and 121 deletions

View file

@ -97,8 +97,8 @@ bundle:
npm run vendor_bundle_js
npm run vendor_minify_js
# increment serviceworker version
sed -i -e "s/CACHE_VERSION =.*/CACHE_VERSION = $$(awk '/CACHE_VERSION =/ { print 1+$$4 }' lnbits/core/static/js/service-worker.js)/" \
lnbits/core/static/js/service-worker.js
sed -i -e "s/CACHE_VERSION =.*/CACHE_VERSION = $$(awk '/CACHE_VERSION =/ { print 1+$$4 }' lnbits/static/js/service-worker.js)/" \
lnbits/static/js/service-worker.js
install-pre-commit-hook:
@echo "Installing pre-commit hook to git"

View file

@ -81,12 +81,10 @@ def create_app() -> FastAPI:
setattr(core_app_extra, "register_new_ext_routes", register_new_ext_routes(app))
setattr(core_app_extra, "register_new_ratelimiter", register_new_ratelimiter(app))
app.mount("/static", StaticFiles(packages=[("lnbits", "static")]), name="static")
app.mount(
"/core/static",
StaticFiles(packages=[("lnbits.core", "static")]),
name="core_static",
)
# register static files
static_path = Path("lnbits", "static")
static = StaticFiles(directory=static_path)
app.mount("/static", static, name="static")
g().base_url = f"http://{settings.host}:{settings.port}"

View file

@ -164,5 +164,5 @@
</q-card>
</q-dialog>
{% endblock %} {% block scripts %} {{ window_vars(user) }}
<script src="/static/js/admin.js"></script>
<script src="{{ static_url_for('static', 'js/admin.js') }}"></script>
{% endblock %}

View file

@ -1,5 +1,5 @@
{% extends "public.html" %} {% block scripts %}
<script src="/core/static/js/index.js"></script>
<script src="{{ static_url_for('static', 'js/index.js') }}"></script>
{% endblock %} {% block page %}
<div class="row q-col-gutter-md justify-center">
<div class="col-12 col-md-7 col-lg-6 q-gutter-y-md">
@ -85,7 +85,7 @@
<a href="https://github.com/ElementsProject/lightning">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/cln.png' : '/static/images/clnl.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/cln.png') }}' : '{{ static_url_for('static', 'images/clnl.png') }}'"
></q-img>
</a>
</div>
@ -93,7 +93,7 @@
<a href="https://github.com/lightningnetwork/lnd">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/lnd.png' : '/static/images/lnd.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/lnd.png') }}' : '{{ static_url_for('static', 'images/lnd.png') }}'"
></q-img>
</a>
</div>
@ -104,7 +104,7 @@
<a href="https://opennode.com">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/opennode.png' : '/static/images/opennodel.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/opennode.png') }}' : '{{ static_url_for('static', 'images/opennodel.png') }}'"
></q-img>
</a>
</div>
@ -112,7 +112,7 @@
<a href="https://lnpay.co/">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/lnpay.png' : '/static/images/lnpayl.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/lnpay.png') }}' : '{{ static_url_for('static', 'images/lnpayl.png') }}'"
></q-img>
</a>
</div>
@ -123,7 +123,7 @@
<a href="https://github.com/rootzoll/raspiblitz">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/blitz.png' : '/static/images/blitzl.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/blitz.png') }}' : '{{ static_url_for('static', 'images/blitzl.png') }}'"
></q-img>
</a>
</div>
@ -131,7 +131,7 @@
<a href="https://start9.com/">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/start9.png' : '/static/images/start9l.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/start9.png') }}' : '{{ static_url_for('static', 'images/start9l.png') }}'"
></q-img>
</a>
</div>
@ -141,7 +141,7 @@
<a href="https://getumbrel.com/">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/umbrel.png' : '/static/images/umbrell.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/umbrel.png') }}' : '{{ static_url_for('static', 'images/umbrell.png') }}'"
></q-img>
</a>
</div>
@ -149,7 +149,7 @@
<a href="https://mynodebtc.com">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/mynode.png' : '/static/images/mynodel.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/mynode.png') }}' : '{{ static_url_for('static', 'images/mynodel.png') }}'"
></q-img>
</a>
</div>
@ -159,7 +159,7 @@
<a href="https://github.com/shesek/spark-wallet">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/spark.png' : '/static/images/sparkl.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/spark.png') }}' : '{{ static_url_for('static', 'images/sparkl.png') }}'"
></q-img>
</a>
</div>
@ -167,7 +167,7 @@
<a href="https://voltage.cloud">
<q-img
contain
:src="($q.dark.isActive) ? '/static/images/voltage.png' : '/static/images/voltagel.png'"
:src="($q.dark.isActive) ? '{{ static_url_for('static', 'images/voltage.png') }}' : '{{ static_url_for('static', 'images/voltagel.png') }}'"
></q-img>
</a>
</div>

View file

@ -3,7 +3,7 @@
{% from "macros.jinja" import window_vars with context %}
<!---->
{% block scripts %} {{ window_vars(user, wallet) }}
<script src="/core/static/js/wallet.js"></script>
<script src="{{ static_url_for('static', 'js/wallet.js') }}"></script>
{% endblock %}
<!---->
{% block title %} {{ wallet.name }} - {{ SITE_TITLE }} {% endblock %}

View file

@ -42,7 +42,7 @@
</div>
{% endblock %} {% block scripts %} {{ window_vars(user) }}
<script src="/core/static/js/node.js"></script>
<script src="{{ static_url_for('static', 'js/node.js') }}"></script>
<script>
Vue.component(VueQrcode.name, VueQrcode)
Vue.use(VueQrcodeReader)

View file

@ -51,7 +51,7 @@ context %} {% block page %}
</div>
{% endblock %} {% block scripts %} {{ window_vars(user) }}
<script src="/core/static/js/node.js"></script>
<script src="{{ static_url_for('static', 'js/node.js') }}"></script>
<script>
Vue.component(VueQrcode.name, VueQrcode)
Vue.use(VueQrcodeReader)

View file

@ -1,5 +1,6 @@
import asyncio
from http import HTTPStatus
from pathlib import Path
from typing import List, Optional
from urllib.parse import urlparse
@ -41,7 +42,7 @@ generic_router = APIRouter(
@generic_router.get("/favicon.ico", response_class=FileResponse)
async def favicon():
return FileResponse("lnbits/core/static/favicon.ico")
return FileResponse(Path("lnbits", "static", "favicon.ico"))
@generic_router.get("/", response_class=HTMLResponse)
@ -329,7 +330,7 @@ async def lnurlwallet(request: Request):
@generic_router.get("/service-worker.js", response_class=FileResponse)
async def service_worker():
return FileResponse("lnbits/core/static/js/service-worker.js")
return FileResponse(Path("lnbits", "static", "js", "service-worker.js"))
@generic_router.get("/manifest/{usr}.webmanifest")

View file

@ -29,6 +29,10 @@ def url_for(endpoint: str, external: Optional[bool] = False, **params: Any) -> s
return url
def static_url_for(static: str, path: str) -> str:
return f"/{static}/{path}?v={settings.server_startup_time}"
def template_renderer(additional_folders: Optional[List] = None) -> Jinja2Templates:
folders = ["lnbits/templates", "lnbits/core/templates"]
if additional_folders:
@ -38,6 +42,7 @@ def template_renderer(additional_folders: Optional[List] = None) -> Jinja2Templa
]
folders.extend(additional_folders)
t = Jinja2Templates(loader=jinja2.FileSystemLoader(folders))
t.env.globals["static_url_for"] = static_url_for
if settings.lnbits_ad_space_enabled:
t.env.globals["AD_SPACE"] = settings.lnbits_ad_space.split(",")
@ -67,8 +72,8 @@ def template_renderer(additional_folders: Optional[List] = None) -> Jinja2Templa
t.env.globals["USE_CUSTOM_LOGO"] = settings.lnbits_custom_logo
if settings.bundle_assets:
t.env.globals["INCLUDED_JS"] = ["/static/bundle.min.js"]
t.env.globals["INCLUDED_CSS"] = ["/static/bundle.min.css"]
t.env.globals["INCLUDED_JS"] = ["bundle.min.js"]
t.env.globals["INCLUDED_CSS"] = ["bundle.min.css"]
else:
vendor_filepath = Path(settings.lnbits_path, "static", "vendor.json")
with open(vendor_filepath) as vendor_file:

View file

@ -6,6 +6,7 @@ import inspect
import json
from os import path
from sqlite3 import Row
from time import time
from typing import Any, List, Optional
import httpx
@ -299,6 +300,7 @@ class EnvSettings(LNbitsSettings):
enable_log_to_file: bool = Field(default=True)
log_rotation: str = Field(default="100 MB")
log_retention: str = Field(default="3 months")
server_startup_time: int = Field(default=time())
@property
def has_default_extension_path(self) -> bool:

File diff suppressed because one or more lines are too long

View file

@ -502,12 +502,6 @@ video {
border-radius: 3px;
}
@font-face {
font-family: "Material Icons";
font-style: normal;
font-weight: 400;
src: url(/static/fonts/material-icons-v50.woff2) format("woff2");
}
.material-icons {
font-family: "Material Icons";
font-weight: normal;

View file

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -1,6 +1,6 @@
// update cache version every time there is a new deployment
// so the service worker reinitializes the cache
const CACHE_VERSION = 65
const CACHE_VERSION = 66
const CURRENT_CACHE = `lnbits-${CACHE_VERSION}-`
const getApiKey = request => {

View file

@ -175,14 +175,6 @@ video {
border-radius: 3px;
}
// Material icons font
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(/static/fonts/material-icons-v50.woff2) format('woff2');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;

View file

@ -1,42 +1,38 @@
{
"js": [
"/static/vendor/moment.js",
"/static/vendor/underscore.js",
"/static/vendor/axios.js",
"/static/vendor/vue.js",
"/static/vendor/vue-router.js",
"/static/vendor/VueQrcodeReader.umd.js",
"/static/vendor/vue-qrcode.js",
"/static/vendor/vuex.js",
"/static/vendor/quasar.ie.polyfills.umd.min.js",
"/static/vendor/quasar.umd.js",
"/static/vendor/Chart.bundle.js",
"/static/vendor/vue-i18n.js",
"/static/vendor/showdown.js",
"/static/i18n/i18n.js",
"/static/i18n/de.js",
"/static/i18n/en.js",
"/static/i18n/es.js",
"/static/i18n/fr.js",
"/static/i18n/it.js",
"/static/i18n/jp.js",
"/static/i18n/cn.js",
"/static/i18n/nl.js",
"/static/i18n/pi.js",
"/static/i18n/pl.js",
"/static/i18n/fr.js",
"/static/i18n/nl.js",
"/static/i18n/we.js",
"/static/i18n/pt.js",
"/static/i18n/br.js",
"/static/js/base.js",
"/static/js/components.js",
"/static/js/components/lnbits-funding-sources.js",
"/static/js/bolt11-decoder.js"
"vendor/moment.js",
"vendor/underscore.js",
"vendor/axios.js",
"vendor/vue.js",
"vendor/vue-router.js",
"vendor/VueQrcodeReader.umd.js",
"vendor/vue-qrcode.js",
"vendor/vuex.js",
"vendor/quasar.ie.polyfills.umd.min.js",
"vendor/quasar.umd.js",
"vendor/Chart.bundle.js",
"vendor/vue-i18n.js",
"vendor/showdown.js",
"i18n/i18n.js",
"i18n/de.js",
"i18n/en.js",
"i18n/es.js",
"i18n/fr.js",
"i18n/it.js",
"i18n/jp.js",
"i18n/cn.js",
"i18n/nl.js",
"i18n/pi.js",
"i18n/pl.js",
"i18n/fr.js",
"i18n/nl.js",
"i18n/we.js",
"i18n/pt.js",
"i18n/br.js",
"js/base.js",
"js/components.js",
"js/components/lnbits-funding-sources.js",
"js/bolt11-decoder.js"
],
"css": [
"/static/vendor/quasar.css",
"/static/vendor/Chart.css",
"/static/css/base.css"
]
"css": ["vendor/quasar.css", "vendor/Chart.css", "css/base.css"]
}

View file

@ -3,8 +3,21 @@
<html lang="en">
<head>
{% for url in INCLUDED_CSS %}
<link rel="stylesheet" type="text/css" href="{{ url }}" />
<link
rel="stylesheet"
type="text/css"
href="{{ static_url_for('static', url ) }}"
/>
{% endfor %} {% block styles %}{% endblock %}
<style>
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url("{{ static_url_for('static', 'fonts/material-icons-v50.woff2') }}")
format('woff2');
}
</style>
<title>{% block title %}{{ SITE_TITLE }}{% endblock %}</title>
<meta charset="utf-8" />
<meta
@ -289,7 +302,7 @@
{% block vue_templates %}{% endblock %}
<!---->
{% for url in INCLUDED_JS %}
<script src="{{ url }}"></script>
<script src="{{ static_url_for('static', url) }}"></script>
{% endfor %}
<!---->
<script type="text/javascript">

View file

@ -4,8 +4,8 @@
"sass": "./node_modules/.bin/sass ./lnbits/static/scss/base.scss > ./lnbits/static/css/base.css",
"vendor_copy": "node -e \"require('./package.json').vendor.forEach((file) => require('fs').copyFileSync(file, './lnbits/static/vendor/'+file.split('/').pop()))\"",
"vendor_json": "node -e \"require('fs').writeFileSync('./lnbits/static/vendor.json', JSON.stringify(require('./package.json').bundle))\"",
"vendor_bundle_css": "node -e \"require('concat')(require('./package.json').bundle.css.map(a => './lnbits/'+a), './lnbits/static/bundle.css')\"",
"vendor_bundle_js": "node -e \"require('concat')(require('./package.json').bundle.js.map(a => './lnbits/'+a), './lnbits/static/bundle.js')\"",
"vendor_bundle_css": "node -e \"require('concat')(require('./package.json').bundle.css.map(a => 'lnbits/static/'+a), './lnbits/static/bundle.css')\"",
"vendor_bundle_js": "node -e \"require('concat')(require('./package.json').bundle.js.map(a => 'lnbits/static/'+a),'./lnbits/static/bundle.js')\"",
"vendor_minify_css": "./node_modules/.bin/minify ./lnbits/static/bundle.css > ./lnbits/static/bundle.min.css",
"vendor_minify_js": "./node_modules/.bin/minify ./lnbits/static/bundle.js > ./lnbits/static/bundle.min.js"
},
@ -49,44 +49,44 @@
],
"bundle": {
"js": [
"/static/vendor/moment.js",
"/static/vendor/underscore.js",
"/static/vendor/axios.js",
"/static/vendor/vue.js",
"/static/vendor/vue-router.js",
"/static/vendor/VueQrcodeReader.umd.js",
"/static/vendor/vue-qrcode.js",
"/static/vendor/vuex.js",
"/static/vendor/quasar.ie.polyfills.umd.min.js",
"/static/vendor/quasar.umd.js",
"/static/vendor/Chart.bundle.js",
"/static/vendor/vue-i18n.js",
"/static/vendor/showdown.js",
"/static/i18n/i18n.js",
"/static/i18n/de.js",
"/static/i18n/en.js",
"/static/i18n/es.js",
"/static/i18n/fr.js",
"/static/i18n/it.js",
"/static/i18n/jp.js",
"/static/i18n/cn.js",
"/static/i18n/nl.js",
"/static/i18n/pi.js",
"/static/i18n/pl.js",
"/static/i18n/fr.js",
"/static/i18n/nl.js",
"/static/i18n/we.js",
"/static/i18n/pt.js",
"/static/i18n/br.js",
"/static/js/base.js",
"/static/js/components.js",
"/static/js/components/lnbits-funding-sources.js",
"/static/js/bolt11-decoder.js"
"vendor/moment.js",
"vendor/underscore.js",
"vendor/axios.js",
"vendor/vue.js",
"vendor/vue-router.js",
"vendor/VueQrcodeReader.umd.js",
"vendor/vue-qrcode.js",
"vendor/vuex.js",
"vendor/quasar.ie.polyfills.umd.min.js",
"vendor/quasar.umd.js",
"vendor/Chart.bundle.js",
"vendor/vue-i18n.js",
"vendor/showdown.js",
"i18n/i18n.js",
"i18n/de.js",
"i18n/en.js",
"i18n/es.js",
"i18n/fr.js",
"i18n/it.js",
"i18n/jp.js",
"i18n/cn.js",
"i18n/nl.js",
"i18n/pi.js",
"i18n/pl.js",
"i18n/fr.js",
"i18n/nl.js",
"i18n/we.js",
"i18n/pt.js",
"i18n/br.js",
"js/base.js",
"js/components.js",
"js/components/lnbits-funding-sources.js",
"js/bolt11-decoder.js"
],
"css": [
"/static/vendor/quasar.css",
"/static/vendor/Chart.css",
"/static/css/base.css"
"vendor/quasar.css",
"vendor/Chart.css",
"css/base.css"
]
}
}