From bd906005e474fa8451eb5cb8531a01148a8da2ad Mon Sep 17 00:00:00 2001 From: Mischa Date: Mon, 22 Jun 2026 23:02:34 +0200 Subject: [PATCH] docs: add asset pipeline implementation plan 8 tasks: build scaffolding, main/map bundles, maplibre-utils extension, template CDN cleanup, and end-to-end verification. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr --- .../plans/2026-06-22-asset-pipeline.md | 967 ++++++++++++++++++ 1 file changed, 967 insertions(+) create mode 100644 docs/working/plans/2026-06-22-asset-pipeline.md diff --git a/docs/working/plans/2026-06-22-asset-pipeline.md b/docs/working/plans/2026-06-22-asset-pipeline.md new file mode 100644 index 0000000..d5aac36 --- /dev/null +++ b/docs/working/plans/2026-06-22-asset-pipeline.md @@ -0,0 +1,967 @@ +# Asset Pipeline & Frontend Reliability Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Eliminate all CDN dependencies, self-host fonts, and deduplicate shared JS logic into versioned bundles built via Docker. + +**Architecture:** esbuild (via throwaway Docker Node container) produces two IIFE bundles — `js/main.js` (universal UI + fonts) and `js/map.js` (MapLibre + GPX utils) — plus extracted CSS in `css-compiled/`. Templates register assets via Grav's Asset Manager instead of hardcoded CDN tags. All duplicated inline JS moves to the main bundle; map init code stays in templates. + +**Tech Stack:** esbuild 0.21+, Node 20 Alpine (Docker only), MapLibre GL 4, PhotoSwipe 5, Scrollama 3, @mapbox/togeojson 0.16, @fontsource-variable/dm-sans, @fontsource/dm-serif-display, Grav 2.0 Asset Manager. + +## Global Constraints + +- All commands run inside Docker — no local Node.js required +- Output files (`js/main.js`, `js/map.js`, `css-compiled/*.css`, `fonts/*.woff2`) are committed to the user/ repo +- `node_modules/` is gitignored +- Working directory for all file edits: `user/themes/intotheeast/` +- All JS bundles use `--format=iife` so templates can reference `maplibregl`, `MapUtils`, `toGeoJSON` as window globals +- Grav Asset Manager is used for all asset registration — no hardcoded ` + + + ``` + +- [ ] **Step 2: Add map_assets block immediately after `{% block content %}`** + +After the opening `{% block content %}` line, add: + +```twig +{% block map_assets %} +{% do assets.addCss('theme://css-compiled/map.css') %} +{% do assets.addJs('theme://js/map.js', {group: 'bottom'}) %} +{% endblock %} +``` + +- [ ] **Step 3: Remove the duplicated JS blocks** + +Remove the following ` + +``` + +Add the map assets block at the very top of the `{% if map_entries|length > 0 %}` block (before the `
`): + +```twig +{% block map_assets %} +{% do assets.addCss('theme://css-compiled/map.css') %} +{% do assets.addJs('theme://js/map.js', {group: 'bottom'}) %} +{% endblock %} +``` + +- [ ] **Step 2: map.html.twig — remove CDN tags, add map_assets block** + +In `user/themes/intotheeast/templates/map.html.twig`: + +Remove lines 39–42: +```html + + + + +``` + +Add after `{% block content %}`: +```twig +{% block map_assets %} +{% do assets.addCss('theme://css-compiled/map.css') %} +{% do assets.addJs('theme://js/map.js', {group: 'bottom'}) %} +{% endblock %} +``` + +- [ ] **Step 3: story.html.twig — remove Scrollama CDN tag** + +In `user/themes/intotheeast/templates/story.html.twig`: + +Remove line 72: +```html + +``` + +Scrollama is now bundled in `main.js` and exposed as `window.scrollama`. The existing inline script that calls `scrollama()` will work unchanged. + +- [ ] **Step 4: Commit** + +```bash +git -C user add themes/intotheeast/templates/partials/feed-map.html.twig themes/intotheeast/templates/map.html.twig themes/intotheeast/templates/story.html.twig +git -C user commit -m "refactor: remove CDN tags from feed-map, map, story templates" +``` + +--- + +### Task 8: End-to-end verification — no external requests, all features intact + +**Files:** None modified. Verification only. + +- [ ] **Step 1: Verify zero external requests on the trip page** + +Open `http://localhost:8081/trips/japan-korea-2026`. Open DevTools → Network tab → reload. + +Check these domains appear zero times: +- `cdn.jsdelivr.net` +- `fonts.googleapis.com` +- `fonts.gstatic.com` + +- [ ] **Step 2: Verify trip page features** + +- Map renders with markers and GPX track +- Marker click scrolls to entry card and flashes it +- Fullscreen map toggle expands/collapses +- Filter bar: All / Journal / Stories each filter correctly +- Sort toggle (↑/↓) reverses feed order +- Stats panel opens and closes (click "Stats ▾" button) +- Cycling panel opens and closes if GPX present ("Cycling ▾" button) +- GPX distance figure populates in stats grid +- Cycling stats grid populates (distance, gain, loss, highest, lowest, moving time, avg speed) +- Back-to-top button appears after scrolling down; click scrolls to top +- Journal photo strip: swipe/scroll dots sync; ‹ › buttons navigate; expand button opens PhotoSwipe; arrow keys advance; click outside closes + +- [ ] **Step 3: Verify story page** + +Open a story URL (e.g. `http://localhost:8081/trips/italy-2026-demo/stories/sorano-rock-and-time`): +- Hero image loads +- Scroll overlay darkens/lightens on scroll +- Story title fades into nav bar as hero scrolls out +- Back-to-top button appears and works +- If page has `.scrolly` sections: they animate on scroll +- No console errors + +- [ ] **Step 4: Check built file sizes** + +```bash +ls -lh user/themes/intotheeast/js/main.js user/themes/intotheeast/js/map.js user/themes/intotheeast/css-compiled/main.css user/themes/intotheeast/css-compiled/map.css +``` + +Rough expected sizes (minified): +- `main.js`: ~80–150 KB (PhotoSwipe + Scrollama + UI code) +- `map.js`: ~600–900 KB (MapLibre GL dominates) +- `main.css`: ~30–60 KB (PhotoSwipe + @font-face rules) +- `map.css`: ~80–120 KB (MapLibre GL styles) + +If `map.js` is unexpectedly small (<100 KB), MapLibre GL may not have bundled — check that `import maplibregl from 'maplibre-gl'` is in `js/src/map.js`. + +- [ ] **Step 5: Final commit** + +```bash +git -C user add -A +git -C user status # confirm only expected files +git -C user commit -m "chore: verify asset pipeline — all CDN deps eliminated" +git add -A +git commit -m "chore: complete asset pipeline — self-hosted deps, deduplicated JS" +```