Files
OneCAD-Draft/scripts/build-web.sh
T
Afonsop 5f9b345ee6 feat: restore-all session recovery, ?file= deep links, offline PWA
Session recovery: more than one pending snapshot adds a 'Restore all'
button to the Recover Drawing modal — every snapshot goes through the
exact same guarded path as a single restore (deleted only after its
own open succeeds). The open-tab list and active tab persist to
localStorage on web (open/save/close) and the remembered tab is
re-selected once a restore batch settles; the modal notes how many
drawings the session had. Nothing is auto-opened.

Deep links: ?file=<url|name> opens a drawing at boot. http(s) URLs
must end in .dwg/.dxf and are fetched with the same streaming,
64 MB-capped, 8 s-deadline reader the remote images use, then go
through the guarded open queue; cross-origin opens announce the
origin first. Bare names resolve from the browser's recent storage,
with a hint when absent. Everything else (file:, javascript:, drive
letters, non-drawing tails) is refused with a console note.

Offline PWA: the app was installable (manifest) but downloaded its
55 MB bundle on every visit. A cache-first service worker now serves
the whole bundle from Cache Storage after one online visit —
navigations network-first so updates land, hashed assets
stale-while-revalidate, non-GET/cross-origin passthrough, old caches
cleaned on activate, and the waiting-worker update flow documented.
The build wrapper stamps the cache version from the bundle hash and
hard-fails if sw.js is missing or unstamped.

Also fixes a locale group mismatch on the DATALINK pick notice
(catalog said a display group that does not exist in the ftl
sources).
2026-09-18 16:27:12 +01:00

73 lines
3.3 KiB
Bash

#!/bin/sh
# Canonical web bundle build: Trunk plus a fonts sanity sync and a service
# worker cache-version stamp.
#
# Trunk's copy-dir pipeline always copies web/fonts in full, but its final
# "apply staging to dist" step wipes the old dist and then moves dist/app/.stage
# into place. If that wipe fails on Windows (typically a transient lock from a
# local file server or antivirus with a file open under dist), the build exits
# non-zero and leaves dist stale with .stage fully populated — easy to miss,
# and a stale bundle would 404 the fonts the app fetches from fonts/*.ttf.
# This wrapper therefore re-syncs web/fonts into dist/app/fonts after a
# successful Trunk build and verifies every font byte-for-byte, so a bundle
# produced through it can never ship without the font set.
#
# The wrapper also stamps the service worker's cache version: web/sw.js ships
# a "v1" placeholder (fine for `trunk serve`), but a deployed bundle must get
# a fresh cache name on every build or clients would keep serving the previous
# deploy's ~55 MB of cached assets. The hash covers every file in the finished
# bundle (fonts re-sync included, sw.js itself excluded), so any content
# change — or any Trunk re-hash of the wasm — produces a new version.
#
# Usage: sh scripts/build-web.sh [extra trunk build args]
# local: sh scripts/build-web.sh
# CI: sh scripts/build-web.sh --locked --html-output index.html web-app.html
set -eu
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$root"
# Git Bash rewrites leading-slash arguments such as --public-url /app/ into
# Windows paths; keep them verbatim. Harmless on other platforms.
MSYS_NO_PATHCONV=1
export MSYS_NO_PATHCONV
trunk build --release --dist dist/app --public-url /app/ "$@"
# Mirror the font sources over the bundle and verify the copy-dir output.
mkdir -p dist/app/fonts
# Hard-fail with a clear message when there are no fonts to verify.
# (find | head -1 survives multiple matches and spaces in paths.)
first_font=$(find web/fonts -name '*.ttf' -print 2>/dev/null | head -n 1)
if [ -z "$first_font" ]; then
echo "build-web.sh: no .ttf fonts found under web/fonts — nothing to ship or verify" >&2
exit 1
fi
cp -f web/fonts/* dist/app/fonts/
count=0
for font in web/fonts/*.ttf; do
name=$(basename "$font")
cmp -s "$font" "dist/app/fonts/$name" || {
echo "error: dist/app/fonts/$name differs from $font" >&2
exit 1
}
count=$((count + 1))
done
# Stamp the service worker's cache version from the finished bundle. Every
# file in dist/app except sw.js itself feeds the hash: the deployed sw.js
# then carries a cache name unique to exactly this bundle's contents, and its
# activate handler deletes any older cache.
[ -f dist/app/sw.js ] || {
echo "build-web.sh: dist/app/sw.js missing — is web/sw.js still listed as a copy-file link in web-app.html?" >&2
exit 1
}
bundle_hash=$(find dist/app -type f ! -name sw.js -print0 | sort -z | xargs -0 sha256sum | sha256sum | cut -c 1-12)
sed -i "s/^const CACHE_VERSION = \"[^\"]*\";/const CACHE_VERSION = \"$bundle_hash\";/" dist/app/sw.js
grep -q "^const CACHE_VERSION = \"$bundle_hash\";" dist/app/sw.js || {
echo "error: failed to stamp the cache version into dist/app/sw.js" >&2
exit 1
}
echo "web bundle built; verified $count fonts in dist/app/fonts; sw.js cache version $bundle_hash"