chore(frontend): toolchain migration checkpoint + UI perf optimizations

Checkpoint of the in-progress frontend toolchain work (Vite pinned to ^6 after
the 7/8 rolldown build break, eslint-plugin-svelte v3 navigation/reactivity
fixes, CI/Dockerfile/manifest updates) together with three UI performance
optimizations (verified on the Vite 6 build):

- Critical CSS: move auth.css/music.css off the global path into their route
  chunks (login/device/nextcloud-login, music) -- -25% gzipped critical CSS
  (~5.4 KB) on every non-auth/non-music page load.
- relativeTimeAgo: cache the Intl.RelativeTimeFormat (was rebuilt per call, once
  per row per render) -- 22.7x faster date formatting in large lists.
- Virtualize search results and grouped trash (list view) via VirtualList -- DOM
  rows mounted stay ~constant (~27) instead of O(N) (94.6% fewer for 500 hits).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DioCrafts
2026-06-21 19:03:07 +02:00
parent 778d551090
commit eef0ef5522
36 changed files with 1147 additions and 1420 deletions
+26 -10
View File
@@ -8,6 +8,30 @@ export interface RelativeTimeOptions {
invalidAsString?: boolean;
}
/** Unit thresholds in seconds, largest first. Hoisted so it isn't rebuilt per call. */
const RELATIVE_UNITS: Array<[Intl.RelativeTimeFormatUnit, number]> = [
['year', 31536000],
['month', 2592000],
['week', 604800],
['day', 86400],
['hour', 3600],
['minute', 60]
];
/**
* Lazily-built, reused `Intl.RelativeTimeFormat`. Constructing one is ~orders of
* magnitude costlier than a `format()` call, and {@link relativeTimeAgo} runs
* once per row per render across large lists — so we build it once (browser
* default locale, matching the previous `undefined` argument) and reuse it.
*/
let relativeFormatter: Intl.RelativeTimeFormat | undefined;
function getRelativeFormatter(): Intl.RelativeTimeFormat {
if (!relativeFormatter) {
relativeFormatter = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });
}
return relativeFormatter;
}
/**
* Locale-aware relative "time ago" via `Intl.RelativeTimeFormat`.
*
@@ -27,16 +51,8 @@ export function relativeTimeAgo(
const diffSec = Math.round((date.getTime() - Date.now()) / 1000);
const abs = Math.abs(diffSec);
const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });
const units: Array<[Intl.RelativeTimeFormatUnit, number]> = [
['year', 31536000],
['month', 2592000],
['week', 604800],
['day', 86400],
['hour', 3600],
['minute', 60]
];
for (const [unit, secs] of units) {
const rtf = getRelativeFormatter();
for (const [unit, secs] of RELATIVE_UNITS) {
if (abs >= secs) return rtf.format(Math.round(diffSec / secs), unit);
}
return rtf.format(diffSec, 'second');