Files
meshcore-analyzer/scripts/instrument-frontend.sh
T
TeTeHackoandClaude Opus 5.5 684f89f200 feat(frontend): serve Leaflet, leaflet.heat and Chart.js from vendor/, not unpkg.com (#2299)
Refs #1554.

`index.html`, `area-map.html` and `geofilter-builder.html` load Leaflet,
leaflet.heat and Chart.js from **unpkg.com** on every page view. That
causes three problems:

- **Privacy:** every visitor sends a request to a third party.
- **Availability:** where unpkg is blocked (script blockers, filtered
networks) or down, the map and every chart are gone. The observer page
then fails with `Error: Chart is not defined`.
- **#1554:** the CSP target there, `script-src 'self'`, blocks these
scripts just like the inline handlers the issue lists, but they are
missing from its inventory.

## Change

- **Vendored libraries:** `public/vendor/leaflet-1.9.4/` (with
`images/`), `vendor/leaflet-heat-0.2.0.js` and
`vendor/chart-4.5.1.umd.min.js`.
- They are the unpkg dist files byte for byte, verified against the SRI
hashes `index.html` already pins.
- The two standalone pages loaded Leaflet without SRI; they now carry
it.
  - This is the same pattern as `vendor/leaflet.markercluster.js`.
- **`.gitattributes`:** `public/vendor/** -text`. Otherwise `* text=auto
eol=lf` rewrites `leaflet.css`, which ships with CRLF, and the browser
refuses it for the integrity mismatch. I hit exactly that while
preparing this.
- **`scripts/instrument-frontend.sh`:** now copies `vendor/`
recursively. The flat `cp public/vendor/*` left the E2E server without
`vendor/leaflet-1.9.4/`, which showed up as `L is not defined`.
- **New test `tests/unit/test-vendored-libs.js`:**
  - no off-site `<script src>` or stylesheet in the served pages
  - every `integrity` attribute matches its vendored file
  - the images Leaflet's stylesheet references exist

  I checked that it fails against the old `index.html`.

## Checks

- `sh test-all.sh` passes.
- These E2E suites pass against the fixture: `test-e2e-playwright.js`,
`test-analytics-fluid-charts.js`, `test-issue-1236-map-mobile-e2e.js`
and `test-issue-1329-map-controls-accordion-e2e.js`.
- On a live instance, a headless browser with `unpkg.com`, `jsdelivr`
and `cdnjs` blocked:
  - the observer page renders all four charts
  - the map loads tiles and markers
  - `typeof L` and `typeof Chart` are defined
  - no CDN request is made and no page error occurs

## Not in this PR

Swagger UI on `/api/docs` (`cmd/server/openapi.go`) still loads
`swagger-ui-dist` from unpkg. I can vendor it in a follow-up if wanted.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 15:43:16 +01:00

46 lines
2.3 KiB
Bash

#!/bin/sh
# Instrument frontend JS for coverage tracking
rm -rf public-instrumented
npx nyc instrument public/ public-instrumented/ --compact=false
# Copy non-JS files (CSS, HTML, images) as-is
cp public/*.css public-instrumented/ 2>/dev/null
cp public/*.html public-instrumented/ 2>/dev/null
cp public/*.svg public-instrumented/ 2>/dev/null
cp public/*.png public-instrumented/ 2>/dev/null
# Copy nested asset directories (e.g. public/img/*.svg used by the new
# CoreScope logo + hero). nyc instrument skips non-JS subdirs entirely,
# so without this the SPA fallback would serve index.html for
# `/img/corescope-logo.svg`, breaking the navbar logo + the
# logo-rebrand E2E (the content-type assertion catches this cleanly).
if [ -d public/img ]; then
mkdir -p public-instrumented/img
cp -r public/img/. public-instrumented/img/
fi
# Copy webfonts (e.g. public/fonts/aldrich-regular.woff2 used by the
# navbar logo SVG @font-face, #1137 follow-up). Same SPA-fallback gotcha
# as /img — without this, GET /fonts/aldrich-regular.woff2 returns
# index.html and the @font-face download fails silently, so the logo
# falls back to monospace and the Aldrich E2E assertion fails.
if [ -d public/fonts ]; then
mkdir -p public-instrumented/fonts
cp -r public/fonts/. public-instrumented/fonts/
fi
# Copy Phosphor icon sprite (#1648 M1). Same SPA-fallback gotcha as /img —
# without this, GET /icons/phosphor-sprite.svg returns index.html and every
# <use href="/icons/phosphor-sprite.svg#ph-…"> shows a broken icon.
if [ -d public/icons ]; then
mkdir -p public-instrumented/icons
cp -r public/icons/. public-instrumented/icons/
fi
# Copy vendored libraries unmodified — `nyc instrument` skips subdirectories
# without a package.json, so vendor/qrcode.js, vendor/jsqr.min.js, etc. are
# never emitted into public-instrumented/. Without them the SPA fallback
# returns index.html for `<script src="vendor/qrcode.js">`, producing
# "Unexpected token '<'" pageerrors and a missing `qrcode` global —
# which makes the QR Generate path hit the "[QR library not loaded]"
# fallback in channel-qr.js (issue #1087 bug 1 manifests in CI only).
# Recursive: Leaflet lives in vendor/leaflet-1.9.4/ with its images/.
mkdir -p public-instrumented/vendor
cp -r public/vendor/. public-instrumented/vendor/
echo "Frontend instrumented successfully"