Improve homepage Lighthouse performance
This commit is contained in:
1 parent
0a27463c7a
commit
8251f98313
268 files changed
+1891
-1740
No files matched your search
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Flatten and minify the site's CSS imports without changing their order.
|
||||
|
||||
The page HTML loads css/main.css. Keeping this file as a generated bundle removes
|
||||
the browser's serial @import chain while the individual files under css/ remain
|
||||
the editable source of truth.
|
||||
"""
|
||||
import argparse
|
||||
import posixpath
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
OUTPUT = ROOT / "css" / "main.css"
|
||||
SOURCE = ROOT / "css" / "source.css"
|
||||
IMPORT_RE = re.compile(r"@import\s+['\"]([^'\"]+\.css)(?:\?v=[0-9a-f]{8})?['\"]\s*;", re.I)
|
||||
URL_RE = re.compile(r"url\(\s*(['\"]?)(\.\.?/[^)'\"\s]+)\1\s*\)", re.I)
|
||||
LIGHTNINGCSS = "lightningcss-cli@1.33.0"
|
||||
|
||||
|
||||
def rebase_urls(css: str, source: str) -> str:
|
||||
"""Make relative url() references resolve from css/main.css after bundling."""
|
||||
source_dir = posixpath.dirname(source)
|
||||
|
||||
def replace(match: re.Match) -> str:
|
||||
quote, value = match.groups()
|
||||
target = posixpath.normpath(posixpath.join(source_dir, value))
|
||||
from_bundle = posixpath.relpath(target, "css")
|
||||
return f"url({quote}{from_bundle}{quote})"
|
||||
|
||||
return URL_RE.sub(replace, css)
|
||||
|
||||
|
||||
def build(output: Path) -> None:
|
||||
source_text = SOURCE.read_text(encoding="utf-8")
|
||||
imports = IMPORT_RE.findall(source_text)
|
||||
if not imports:
|
||||
raise RuntimeError("css/source.css has no CSS imports to bundle")
|
||||
chunks = []
|
||||
for import_path in imports:
|
||||
rel = posixpath.normpath(posixpath.join("css", import_path))
|
||||
path = ROOT / rel
|
||||
if not path.is_file():
|
||||
raise FileNotFoundError(f"Missing CSS source: {rel}")
|
||||
chunks.append(rebase_urls(path.read_text(encoding="utf-8"), rel))
|
||||
input_path = ROOT / "css" / ".main.build.css"
|
||||
input_path.write_text("\n".join(chunks), encoding="utf-8", newline="\n")
|
||||
try:
|
||||
subprocess.run(
|
||||
["npx", "--yes", LIGHTNINGCSS, str(input_path), "--minify", "--output-file", str(output)],
|
||||
cwd=ROOT,
|
||||
check=True,
|
||||
)
|
||||
finally:
|
||||
input_path.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--check", action="store_true", help="fail if css/main.css is stale")
|
||||
args = parser.parse_args()
|
||||
if not SOURCE.is_file():
|
||||
raise FileNotFoundError("Missing CSS source aggregator: css/source.css")
|
||||
if args.check:
|
||||
with tempfile.NamedTemporaryFile(prefix="msos-main-", suffix=".css", dir=ROOT / "css", delete=False) as tmp:
|
||||
temp_output = Path(tmp.name)
|
||||
try:
|
||||
build(temp_output)
|
||||
if temp_output.read_bytes() != OUTPUT.read_bytes():
|
||||
print("css/main.css is stale; run tools/build_css_bundle.py", file=sys.stderr)
|
||||
return 1
|
||||
finally:
|
||||
temp_output.unlink(missing_ok=True)
|
||||
print(f"CSS bundle is current ({OUTPUT.stat().st_size:,} bytes)")
|
||||
return 0
|
||||
build(OUTPUT)
|
||||
print(f"Wrote css/main.css ({OUTPUT.stat().st_size:,} bytes)")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as exc:
|
||||
print(f"CSS bundle failed: {exc}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
@@ -37,6 +37,7 @@ BUILD_STEPS = [
|
||||
("Inject SEO + rebuild sitemap/robots", ["tools/seo_inject.py", "--all", "--sitemap"]),
|
||||
("Rebuild bot/AI discovery files", ["tools/build_botlinks.py"]),
|
||||
("Rebuild offline assistant search index", ["tools/build_search_index.py"]),
|
||||
("Bundle and minify CSS", ["tools/build_css_bundle.py"]),
|
||||
# Last: stamp a content-hash ?v= on local CSS/JS refs so deploys aren't
|
||||
# served stale from cache. Must run after every step that writes pages.
|
||||
("Cache-bust CSS/JS references", ["tools/cache_bust.py"]),
|
||||
|
||||
Reference in new issue
Block a user