[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_bundle_js
npm run vendor_minify_js npm run vendor_minify_js
# increment serviceworker version # increment serviceworker version
sed -i -e "s/CACHE_VERSION =.*/CACHE_VERSION = $$(awk '/CACHE_VERSION =/ { print 1+$$4 }' 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/core/static/js/service-worker.js lnbits/static/js/service-worker.js
install-pre-commit-hook: install-pre-commit-hook:
@echo "Installing pre-commit hook to git" @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_ext_routes", register_new_ext_routes(app))
setattr(core_app_extra, "register_new_ratelimiter", register_new_ratelimiter(app)) setattr(core_app_extra, "register_new_ratelimiter", register_new_ratelimiter(app))
app.mount("/static", StaticFiles(packages=[("lnbits", "static")]), name="static") # register static files
app.mount( static_path = Path("lnbits", "static")
"/core/static", static = StaticFiles(directory=static_path)
StaticFiles(packages=[("lnbits.core", "static")]), app.mount("/static", static, name="static")
name="core_static",
)
g().base_url = f"http://{settings.host}:{settings.port}" g().base_url = f"http://{settings.host}:{settings.port}"

View File

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

View File

@ -1,5 +1,5 @@
{% extends "public.html" %} {% block scripts %} {% 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 %} {% endblock %} {% block page %}
<div class="row q-col-gutter-md justify-center"> <div class="row q-col-gutter-md justify-center">
<div class="col-12 col-md-7 col-lg-6 q-gutter-y-md"> <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"> <a href="https://github.com/ElementsProject/lightning">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -93,7 +93,7 @@
<a href="https://github.com/lightningnetwork/lnd"> <a href="https://github.com/lightningnetwork/lnd">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -104,7 +104,7 @@
<a href="https://opennode.com"> <a href="https://opennode.com">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -112,7 +112,7 @@
<a href="https://lnpay.co/"> <a href="https://lnpay.co/">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -123,7 +123,7 @@
<a href="https://github.com/rootzoll/raspiblitz"> <a href="https://github.com/rootzoll/raspiblitz">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -131,7 +131,7 @@
<a href="https://start9.com/"> <a href="https://start9.com/">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -141,7 +141,7 @@
<a href="https://getumbrel.com/"> <a href="https://getumbrel.com/">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -149,7 +149,7 @@
<a href="https://mynodebtc.com"> <a href="https://mynodebtc.com">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -159,7 +159,7 @@
<a href="https://github.com/shesek/spark-wallet"> <a href="https://github.com/shesek/spark-wallet">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>
@ -167,7 +167,7 @@
<a href="https://voltage.cloud"> <a href="https://voltage.cloud">
<q-img <q-img
contain 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> ></q-img>
</a> </a>
</div> </div>

View File

@ -3,7 +3,7 @@
{% from "macros.jinja" import window_vars with context %} {% from "macros.jinja" import window_vars with context %}
<!----> <!---->
{% block scripts %} {{ window_vars(user, wallet) }} {% 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 %} {% endblock %}
<!----> <!---->
{% block title %} {{ wallet.name }} - {{ SITE_TITLE }} {% endblock %} {% block title %} {{ wallet.name }} - {{ SITE_TITLE }} {% endblock %}

View File

@ -42,7 +42,7 @@
</div> </div>
{% endblock %} {% block scripts %} {{ window_vars(user) }} {% 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> <script>
Vue.component(VueQrcode.name, VueQrcode) Vue.component(VueQrcode.name, VueQrcode)
Vue.use(VueQrcodeReader) Vue.use(VueQrcodeReader)

View File

@ -51,7 +51,7 @@ context %} {% block page %}
</div> </div>
{% endblock %} {% block scripts %} {{ window_vars(user) }} {% 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> <script>
Vue.component(VueQrcode.name, VueQrcode) Vue.component(VueQrcode.name, VueQrcode)
Vue.use(VueQrcodeReader) Vue.use(VueQrcodeReader)

View File

@ -1,5 +1,6 @@
import asyncio import asyncio
from http import HTTPStatus from http import HTTPStatus
from pathlib import Path
from typing import List, Optional from typing import List, Optional
from urllib.parse import urlparse from urllib.parse import urlparse
@ -41,7 +42,7 @@ generic_router = APIRouter(
@generic_router.get("/favicon.ico", response_class=FileResponse) @generic_router.get("/favicon.ico", response_class=FileResponse)
async def favicon(): async def favicon():
return FileResponse("lnbits/core/static/favicon.ico") return FileResponse(Path("lnbits", "static", "favicon.ico"))
@generic_router.get("/", response_class=HTMLResponse) @generic_router.get("/", response_class=HTMLResponse)
@ -329,7 +330,7 @@ async def lnurlwallet(request: Request):
@generic_router.get("/service-worker.js", response_class=FileResponse) @generic_router.get("/service-worker.js", response_class=FileResponse)
async def service_worker(): 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") @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 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: def template_renderer(additional_folders: Optional[List] = None) -> Jinja2Templates:
folders = ["lnbits/templates", "lnbits/core/templates"] folders = ["lnbits/templates", "lnbits/core/templates"]
if additional_folders: if additional_folders:
@ -38,6 +42,7 @@ def template_renderer(additional_folders: Optional[List] = None) -> Jinja2Templa
] ]
folders.extend(additional_folders) folders.extend(additional_folders)
t = Jinja2Templates(loader=jinja2.FileSystemLoader(folders)) t = Jinja2Templates(loader=jinja2.FileSystemLoader(folders))
t.env.globals["static_url_for"] = static_url_for
if settings.lnbits_ad_space_enabled: if settings.lnbits_ad_space_enabled:
t.env.globals["AD_SPACE"] = settings.lnbits_ad_space.split(",") 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 t.env.globals["USE_CUSTOM_LOGO"] = settings.lnbits_custom_logo
if settings.bundle_assets: if settings.bundle_assets:
t.env.globals["INCLUDED_JS"] = ["/static/bundle.min.js"] t.env.globals["INCLUDED_JS"] = ["bundle.min.js"]
t.env.globals["INCLUDED_CSS"] = ["/static/bundle.min.css"] t.env.globals["INCLUDED_CSS"] = ["bundle.min.css"]
else: else:
vendor_filepath = Path(settings.lnbits_path, "static", "vendor.json") vendor_filepath = Path(settings.lnbits_path, "static", "vendor.json")
with open(vendor_filepath) as vendor_file: with open(vendor_filepath) as vendor_file:

View File

@ -6,6 +6,7 @@ import inspect
import json import json
from os import path from os import path
from sqlite3 import Row from sqlite3 import Row
from time import time
from typing import Any, List, Optional from typing import Any, List, Optional
import httpx import httpx
@ -299,6 +300,7 @@ class EnvSettings(LNbitsSettings):
enable_log_to_file: bool = Field(default=True) enable_log_to_file: bool = Field(default=True)
log_rotation: str = Field(default="100 MB") log_rotation: str = Field(default="100 MB")
log_retention: str = Field(default="3 months") log_retention: str = Field(default="3 months")
server_startup_time: int = Field(default=time())
@property @property
def has_default_extension_path(self) -> bool: 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; 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 { .material-icons {
font-family: "Material Icons"; font-family: "Material Icons";
font-weight: normal; 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 // update cache version every time there is a new deployment
// so the service worker reinitializes the cache // so the service worker reinitializes the cache
const CACHE_VERSION = 65 const CACHE_VERSION = 66
const CURRENT_CACHE = `lnbits-${CACHE_VERSION}-` const CURRENT_CACHE = `lnbits-${CACHE_VERSION}-`
const getApiKey = request => { const getApiKey = request => {

View File

@ -175,14 +175,6 @@ video {
border-radius: 3px; 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 { .material-icons {
font-family: 'Material Icons'; font-family: 'Material Icons';
font-weight: normal; font-weight: normal;

View File

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

View File

@ -3,8 +3,21 @@
<html lang="en"> <html lang="en">
<head> <head>
{% for url in INCLUDED_CSS %} {% 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 %} {% 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> <title>{% block title %}{{ SITE_TITLE }}{% endblock %}</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta <meta
@ -289,7 +302,7 @@
{% block vue_templates %}{% endblock %} {% block vue_templates %}{% endblock %}
<!----> <!---->
{% for url in INCLUDED_JS %} {% for url in INCLUDED_JS %}
<script src="{{ url }}"></script> <script src="{{ static_url_for('static', url) }}"></script>
{% endfor %} {% endfor %}
<!----> <!---->
<script type="text/javascript"> <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", "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_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_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_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/'+a), './lnbits/static/bundle.js')\"", "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_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" "vendor_minify_js": "./node_modules/.bin/minify ./lnbits/static/bundle.js > ./lnbits/static/bundle.min.js"
}, },
@ -49,44 +49,44 @@
], ],
"bundle": { "bundle": {
"js": [ "js": [
"/static/vendor/moment.js", "vendor/moment.js",
"/static/vendor/underscore.js", "vendor/underscore.js",
"/static/vendor/axios.js", "vendor/axios.js",
"/static/vendor/vue.js", "vendor/vue.js",
"/static/vendor/vue-router.js", "vendor/vue-router.js",
"/static/vendor/VueQrcodeReader.umd.js", "vendor/VueQrcodeReader.umd.js",
"/static/vendor/vue-qrcode.js", "vendor/vue-qrcode.js",
"/static/vendor/vuex.js", "vendor/vuex.js",
"/static/vendor/quasar.ie.polyfills.umd.min.js", "vendor/quasar.ie.polyfills.umd.min.js",
"/static/vendor/quasar.umd.js", "vendor/quasar.umd.js",
"/static/vendor/Chart.bundle.js", "vendor/Chart.bundle.js",
"/static/vendor/vue-i18n.js", "vendor/vue-i18n.js",
"/static/vendor/showdown.js", "vendor/showdown.js",
"/static/i18n/i18n.js", "i18n/i18n.js",
"/static/i18n/de.js", "i18n/de.js",
"/static/i18n/en.js", "i18n/en.js",
"/static/i18n/es.js", "i18n/es.js",
"/static/i18n/fr.js", "i18n/fr.js",
"/static/i18n/it.js", "i18n/it.js",
"/static/i18n/jp.js", "i18n/jp.js",
"/static/i18n/cn.js", "i18n/cn.js",
"/static/i18n/nl.js", "i18n/nl.js",
"/static/i18n/pi.js", "i18n/pi.js",
"/static/i18n/pl.js", "i18n/pl.js",
"/static/i18n/fr.js", "i18n/fr.js",
"/static/i18n/nl.js", "i18n/nl.js",
"/static/i18n/we.js", "i18n/we.js",
"/static/i18n/pt.js", "i18n/pt.js",
"/static/i18n/br.js", "i18n/br.js",
"/static/js/base.js", "js/base.js",
"/static/js/components.js", "js/components.js",
"/static/js/components/lnbits-funding-sources.js", "js/components/lnbits-funding-sources.js",
"/static/js/bolt11-decoder.js" "js/bolt11-decoder.js"
], ],
"css": [ "css": [
"/static/vendor/quasar.css", "vendor/quasar.css",
"/static/vendor/Chart.css", "vendor/Chart.css",
"/static/css/base.css" "css/base.css"
] ]
} }
} }