perf(widgets): stop building hidden tab panels, and drop a third-party image fallback

Mantine's Tabs keeps inactive panels mounted by default. On Mantine 9 with
React 19 that uses <Activity>, which preserves state and unmounts effects but
still builds the entire subtree - so a two-tab widget pays for both while
showing one.

  health-monitoring  both the system and the cluster monitoring view were built
  media-missing      both tabs built their full card list, each card with a
                     poster and a blurred backdrop

Two other Tabs users are deliberately left mounted: custom-api panels can hold
user component state, and the widget edit modal would reset half-filled forms.

media-missing also rendered every card into a scrolling tile with no lazy
loading, the same shape as media-releases. Its card height is fixed per density,
so contain-intrinsic-size is exact rather than a guess.

calendar fell back to https://placehold.co/400x400 when a poster failed to
load, so a self-hosted dashboard made a third-party request - once per failing
event - to draw a grey square, and showed nothing at all on a host without
internet access. Same grey square, inline.

The rss feed handler logged the whole serialised feed entry through a raw
console.debug, which no log level could suppress, and reported a match count
that was really the regex capture-group count.

Adds scripts/benchmarks/widget-inventory.mjs and docs/perf/WIDGET-AUDIT.md, a
verdict for all 50 widgets.
This commit is contained in:
Thomas Camlong committed 2026-08-11 16:30:22 +02:00
1 parent cf240addea
commit ec79a15023
6 files changed
+380 -20

No files matched your search

+4 -3
View File
@@ -46,9 +46,10 @@ const getImageFromStringAsFallback = (feedUrl: string, content: string) => {
return null;
}
console.debug(
`Falling back to regex image search for '${feedUrl}'. Found ${result.length} matches in content: ${content}`,
);
// This used to log the entire serialised feed entry through a raw console.debug, so it could not be
// suppressed by log level and produced one enormous line per entry of every feed. It also reported
// `result.length`, which is the capture-group count and so was always 2 rather than a match count.
logger.debug(`Falling back to regex image search for '${feedUrl}'`, { image: result[0] });
return result[0];
};