37 lines
3.5 KiB
Python
37 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Regenerate index.html CSS/script tags and service-worker.js from app_manifest.json.
|
|
This project intentionally stays buildless; this script is a lightweight manifest sync tool.
|
|
"""
|
|
from __future__ import annotations
|
|
from pathlib import Path
|
|
import json
|
|
import re
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
manifest = json.loads((ROOT / "app_manifest.json").read_text(encoding="utf-8"))
|
|
version = manifest["version"]
|
|
css_files = manifest["css"]
|
|
js_files = manifest["js"]
|
|
|
|
index = ROOT / "index.html"
|
|
s = index.read_text(encoding="utf-8")
|
|
css_block = "".join([f'\n <link rel="stylesheet" href="{f}?v={version}" />' for f in css_files])
|
|
s = re.sub(
|
|
r'\s*<link rel="stylesheet" href="css/[^\"]+" />(?:\s*<link rel="stylesheet" href="css/[^\"]+" />)*',
|
|
css_block,
|
|
s,
|
|
count=1,
|
|
)
|
|
script_block = "\n".join([f' <script src="{f}?v={version}" defer></script>' for f in js_files])
|
|
s = re.sub(
|
|
r'\n\s*<script src="js/version\.js\?v=[^\"]+" defer></script>[\s\S]*?\n\s*<script src="js/debug_tools\.js\?v=[^\"]+" defer></script>',
|
|
"\n" + script_block,
|
|
s,
|
|
count=1,
|
|
)
|
|
index.write_text(s, encoding="utf-8")
|
|
|
|
core_names = [Path(f).stem for f in js_files]
|
|
css_entries = ",\n ".join([f'`./{f}?${{v}}`' for f in css_files])
|
|
js_names = ", ".join([json.dumps(n, ensure_ascii=False) for n in core_names])
|
|
(ROOT / "service-worker.js").write_text(f'''"use strict";\n\nconst APP_VERSION = "{version}";\nconst CACHE_NAME = `tarinai-colony-${{APP_VERSION}}`;\nconst v = `v=${{APP_VERSION}}`;\n// Generated from app_manifest.json. Run scripts/generate_app_files.py after changing static files.\nconst coreScriptNames = [\n {js_names}\n];\nconst CORE_ASSETS = [\n "./",\n "./index.html",\n {css_entries},\n ...coreScriptNames.map(name => `./js/${{name}}.js?${{v}}`),\n];\n\nself.addEventListener("install", (event) => {{\n event.waitUntil(caches.open(CACHE_NAME).then(cache => cache.addAll(CORE_ASSETS)).catch(() => undefined));\n self.skipWaiting();\n}});\n\nself.addEventListener("activate", (event) => {{\n event.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(key => key !== CACHE_NAME).map(key => caches.delete(key)))));\n self.clients.claim();\n}});\n\nfunction isStaticAsset(request) {{\n const url = new URL(request.url);\n return /\\.(?:js|css|webp|png|jpg|jpeg|gif|svg|mp3|wav|woff2?)$/i.test(url.pathname);\n}}\n\nfunction cacheableResponse(response) {{\n return response && response.status === 200 && response.type !== "opaque";\n}}\n\nfunction putCacheSafely(request, response) {{\n if (!cacheableResponse(response)) return Promise.resolve(false);\n return caches.open(CACHE_NAME).then(cache => cache.put(request, response.clone())).then(() => true).catch(() => false);\n}}\n\nself.addEventListener("fetch", (event) => {{\n const request = event.request;\n if (request.method !== "GET") return;\n const url = new URL(request.url);\n if (url.origin !== self.location.origin) return;\n if (/service-worker\\.js$/i.test(url.pathname)) return;\n if (request.mode === "navigate" || /index\\.html$/i.test(url.pathname)) {{\n event.respondWith(fetch(request).then(response => {{\n putCacheSafely(request, response);\n return response;\n }}).catch(() => caches.match(request).then(cached => cached || caches.match("./index.html"))));\n return;\n }}\n if (isStaticAsset(request)) {{\n event.respondWith(caches.match(request).then(cached => cached || fetch(request).then(response => {{\n putCacheSafely(request, response);\n return response;\n }})));\n }}\n}});\n''', encoding="utf-8")
|