diff --git a/Dockerfile b/Dockerfile index 7639ac2..4a59cde 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM python:3.13-slim AS builder WORKDIR /app COPY . . +RUN apt-get update && apt-get install -y nodejs npm && npm install -g terser clean-css-cli RUN pip install --no-cache-dir -r ./requirements.txt RUN zensical build RUN rm ./deploy/sitemap.xml diff --git a/minify.py b/minify.py index fce7588..99e1a90 100755 --- a/minify.py +++ b/minify.py @@ -2,30 +2,75 @@ """Minify CSS, JS, and HTML files in the deploy directory in-place.""" import re +import subprocess import sys from pathlib import Path -import rcssmin -import rjsmin - DEPLOY_DIR = Path("./deploy") -def minify_html_content(content): - content = re.sub(r"", "", content, flags=re.DOTALL) # remove comments - content = re.sub(r">\s+<", "><", content) # collapse whitespace between tags - content = re.sub(r"\s{2,}", " ", content) # collapse remaining whitespace - return content.strip() +def minify_css(content): + result = subprocess.run( + ["cleancss"], + input=content, + capture_output=True, + text=True, + ) + if result.returncode != 0: + print(f" cleancss error: {result.stderr}", file=sys.stderr) + return content + return result.stdout + + +def minify_js(content): + result = subprocess.run( + ["terser", "--compress", "--mangle"], + input=content, + capture_output=True, + text=True, + ) + if result.returncode != 0: + print(f" terser error: {result.stderr}", file=sys.stderr) + return content + return result.stdout + + +def minify_html(content): + # Extract and preserve
and blocks before minifying
+ preserved = {}
+
+ def preserve(match):
+ key = f"\x00PRESERVE{len(preserved)}\x00"
+ preserved[key] = match.group(0)
+ return key
+
+ content = re.sub(r"", preserve, content, flags=re.IGNORECASE)
+ content = re.sub(r"", preserve, content, flags=re.IGNORECASE)
+
+ # Minify everything else
+ content = re.sub(r"", "", content, flags=re.DOTALL)
+ content = " ".join(line.strip() for line in content.splitlines())
+ content = re.sub(r">\s+<", "><", content)
+ content = re.sub(r"\s{2,}", " ", content)
+ content = content.strip()
+
+ # Restore preserved blocks untouched
+ for key, value in preserved.items():
+ content = content.replace(key, value)
+
+ return content
+
+
+HANDLERS = {
+ ".css": minify_css,
+ ".js": minify_js,
+ ".html": minify_html,
+}
def minify_files():
- handlers = {
- ".css": lambda c: rcssmin.cssmin(c),
- ".js": lambda c: rjsmin.jsmin(c, keep_bang_comments=False),
- ".html": minify_html_content,
- }
for file in DEPLOY_DIR.rglob("*"):
- handler = handlers.get(file.suffix)
+ handler = HANDLERS.get(file.suffix)
if not handler:
continue
content = file.read_text(encoding="utf-8")
diff --git a/requirements.txt b/requirements.txt
index aba80f0..351c3ca 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -22,8 +22,6 @@ pymdown-extensions==10.21
python-dateutil==2.9.0.post0
PyYAML==6.0.3
pyyaml_env_tag==1.1
-rcssmin==1.2.2
-rjsmin==1.2.4
six==1.17.0
watchdog==6.0.0
zensical==0.0.27