make injection script template a data file

This commit is contained in:
Daniel Fichtinger 2025-07-13 16:54:04 -04:00
parent 585a987c3f
commit 1c64d1f431
3 changed files with 49 additions and 15 deletions

View file

@ -0,0 +1,6 @@
const ws = new WebSocket("__SOCKET_ADDRESS_");
ws.onmessage = event => {
if (event.data === "reload") {
location.reload();
}
};

View file

@ -13,6 +13,7 @@ from rich import print
from watchdog.events import FileSystemEvent, FileSystemEventHandler
from watchdog.observers import Observer
from zona import util
from zona.builder import ZonaBuilder
from zona.log import get_logger
from zona.websockets import WebSocketServer
@ -22,16 +23,16 @@ logger = get_logger()
def make_reload_script(host: str, port: int) -> str:
"""Generates the JavaScript that must be injected into HTML pages for the live reloading to work."""
return f"""
<script>
const ws = new WebSocket("ws://{host}:{port}");
ws.onmessage = event => {{
if (event.data === "reload") {{
location.reload();
}}
}};
</script>
"""
js = util.get_resource("server/inject.js").contents
js = util.minify_js(js)
address = f"ws://{host}:{port}"
for placeholder, value in (("__SOCKET_ADDRESS_", address),):
if placeholder not in js:
raise ValueError(
f"{placeholder} missing from reload script template!"
)
js = js.replace(placeholder, value)
return f"<script>{js}</script>"
def make_handler_class(script: str):

View file

@ -1,4 +1,5 @@
import fnmatch
import re
import string
from importlib import resources
from importlib.resources.abc import Traversable
@ -12,6 +13,15 @@ class ZonaResource(NamedTuple):
contents: str
def get_resource(path: str) -> ZonaResource:
"""Load the packaged resource in data/path"""
file = resources.files("zona").joinpath("data", path)
if file.is_file():
return ZonaResource(name=path, contents=file.read_text())
else:
raise FileNotFoundError(f"{path} is not a valid Zona resource!")
def get_resources(subdir: str) -> list[ZonaResource]:
"""Load the packaged resources in data/subdir"""
out: list[ZonaResource] = []
@ -65,11 +75,28 @@ def normalize_url(url: str) -> str:
return url
def should_ignore(
path: Path, patterns: list[str], base: Path
) -> bool:
def should_ignore(path: Path, patterns: list[str], base: Path) -> bool:
rel_path = path.relative_to(base)
return any(
fnmatch.fnmatch(str(rel_path), pattern)
for pattern in patterns
fnmatch.fnmatch(str(rel_path), pattern) for pattern in patterns
)
MINIFY_JS_PATTERN = re.compile(
r"""
//.*?$ |
/\*.*?\*/ |
\s+
""",
re.MULTILINE | re.DOTALL | re.VERBOSE,
)
def minify_js(js: str) -> str:
"""Naively minifies JavaScript by stripping comments and whitespace."""
return MINIFY_JS_PATTERN.sub(
# replace whitespace with single space,
# strip comments
lambda m: " " if m.group(0).isspace() else "",
js,
).strip()