From 8a3eb50300607dbd0af163fda616e1c2df7369df Mon Sep 17 00:00:00 2001 From: yumoqing Date: Tue, 25 Aug 2026 14:36:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(assets):=20=E6=B3=A8=E5=86=8C=20assets=5Fv?= =?UTF-8?q?er()=20=E5=85=A8=E5=B1=80=E5=87=BD=E6=95=B0(js/css=20=E6=9C=80?= =?UTF-8?q?=E5=A4=A7=20mtime,=2030s=20=E7=BC=93=E5=AD=98)=EF=BC=8C?= =?UTF-8?q?=E6=A0=B9=E6=B2=BB=E6=94=B9=E4=BA=86=E5=89=8D=E7=AB=AF=20js=20?= =?UTF-8?q?=E6=B5=8F=E8=A7=88=E5=99=A8=E4=BB=8D=E8=B7=91=E6=97=A7=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/global_func.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/app/global_func.py b/app/global_func.py index fdf8779..39a16bf 100644 --- a/app/global_func.py +++ b/app/global_func.py @@ -1,8 +1,66 @@ +import os +import time + from ahserver.serverenv import ServerEnv from ahserver.globalEnv import initEnv, password_encode as _password_encode +from appPublic.jsonConfig import getConfig DBNAME = "pipeline" +# 静态资源缓存版本号:取所有应用级 js/css 与 bricks 主文件的最大 mtime。 +# 浏览器对无 Cache-Control 的静态文件走启发式缓存,改了 js 用户仍跑旧代码; +# 这里把 mtime 作为 ?v= 参数注入 header.tmpl,部署后自动失效,无需手工 bump 版本号。 +_ASSETS_VER_TTL = 30 +_assets_ver_cache = {'ver': None, 'ts': 0.0} + + +def _asset_ospaths(): + """把 jsfiles()/cssfiles() 的 url 路径映射回磁盘路径(含 bricks 主文件)。""" + g = ServerEnv() + config = getConfig() + roots = [] + for item in (config.website.paths or []): + roots.append(item[0] if isinstance(item, (list, tuple)) else item) + + urls = ['/bricks/bricks.js', '/bricks/css/bricks.css'] + for name in ('jsfiles', 'cssfiles'): + f = g.get(name) + if not callable(f): + continue + try: + urls += list(f() or []) + except Exception: + pass + + for u in urls: + for root in roots: + fp = root + u + if os.path.isfile(fp): + yield fp + break + + +def assets_ver(): + """静态资源版本号(字符串),30 秒内复用缓存结果。""" + now = time.time() + if _assets_ver_cache['ver'] and now - _assets_ver_cache['ts'] < _ASSETS_VER_TTL: + return _assets_ver_cache['ver'] + mx = 0 + try: + for fp in _asset_ospaths(): + try: + m = os.path.getmtime(fp) + except OSError: + continue + if m > mx: + mx = m + except Exception: + mx = 0 + ver = str(int(mx)) if mx else str(int(now)) + _assets_ver_cache['ver'] = ver + _assets_ver_cache['ts'] = now + return ver + def password_encode(s): """Wrapper to handle None input during login form load.""" @@ -20,3 +78,4 @@ def set_globalvariable(): g = ServerEnv() g.get_module_dbname = get_module_dbname g.password_encode = password_encode + g.assets_ver = assets_ver