Date: 2026-05-18
22 standalone mini-apps (apps/zen*.html) needed to be published as installable PWAs at the site root, each with:
One Tailwind build for all zen apps — rejected. Any class used in any zen app would leak into every other app’s stylesheet. Purge must be scoped per-app.
CDN Tailwind in production — rejected. CDN adds an external runtime dependency, fails offline (PWAs should work offline), and blocks display: standalone from looking native.
Fold into build-apps-css.js — rejected. That script has no Cloudflare skip gate and runs unconditionally. We needed a separate entry point with an env-var kill switch.
_scripts/pwa-zen-apps.jsReads every apps/zen*.html, creates <site-root>/<slug>/ with:
index.html — copy of source + manifest link + PWA meta tags + floating apps-menu button + SW registrationmanifest.json — extracted title/theme-color, scope ./, lang: ar, dir: rtlsw.js — cache-first service worker scoped to ./TODO.md — per-app task tracking stubAlso writes apps/registry.json (all apps as JSON) and apps/index.html (gallery page that fetches registry).
Key decision: PWA_DIR = ROOT (site root), not apps/. The /apps/ path is only for the source files.
_scripts/build-zen-css.jsRuns after pwa-zen-apps.js. For each zen*/ dir at site root:
BUILD_ZEN_APPS env var — exits immediately if false or 0npx tailwindcss -i assets/css/tailwind.src.css -o <slug>/style.css --content <slug>/index.html --minify<script> tag from index.html (idempotent — safe to run twice)<link rel="stylesheet" href="./style.css"> before </head> if not already present.no-app-css marker so build-apps-css.js skips the dir (no double-processing)_data/domain_protection.jsonAll 22 zen slugs added to protected_folders. inject-protection.js reads this during build:protect and applies the domain-lock snippet to _site/<slug>/index.html post-build.
package.json"build:zen:css": "node _scripts/build-zen-css.js"
Inserted into the main build pipeline between build:css:apps and build:jekyll.
Full pipeline:
build:css → build:css:apps → build:zen:css → build:jekyll → build:protect → build:pwa
Apps created in apps/zen*/ instead of site root — initial script had PWA_DIR = APPS_DIR. User caught it. Fixed by moving dirs with mv apps/zen*/ . and updating PWA_DIR = ROOT in the script.
zencalc nested into itself — existing zencalc/ at site root caused mv apps/zencalc/ . to create zencalc/zencalc/. Fixed by rm -rf zencalc/zencalc. The pre-existing zencalc/ was already a proper PWA and was left untouched.
_site/ output, jekyll build pipeline)--content glob = what HTML to scan for classes)Set BUILD_ZEN_APPS=false in Cloudflare Pages environment variables to skip zen CSS builds on every main-site deploy. Run locally with npm run build:zen:css when zen app HTML actually changes.