From 182be8c33d4f96c2a41eaea53d9d0b66c7cb8bb7 Mon Sep 17 00:00:00 2001 From: librelad Date: Fri, 29 May 2026 23:02:24 +0100 Subject: [PATCH] =?UTF-8?q?feat(webui):=20phase=203=20(first=20feature)=20?= =?UTF-8?q?=E2=80=94=20migrate=20Backup=20to=20a=20feature=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces the kernel lifecycle and migrates the first real page to the feature-module contract: - kernel/lifecycle.js: MountContext (loadScripts/loadFragment/setContent + an AbortController/unsub teardown ledger so mounts can't leak listeners or live streams). - features/backup/index.js: Backup Center as a self-contained module (LP.features.register with mount/unmount); heavy backup-page.js stays lazy-loaded on first mount. - spa.js: routes whose feature has a registered mount() are driven through the kernel; everything else still uses its legacy handleX(). navigate() unmounts the current feature first. Both fall back to the legacy handler if a module is missing or mount throws. Strangler step: /backup now flows manifest -> registry -> mount/unmount. The other pages are untouched. handleBackup remains as the fallback. Co-Authored-By: Claude Opus 4.8 Signed-off-by: librelad --- .../frontend/features/backup/index.js | 41 +++++++++++ containers/libreportal/frontend/index.html | 4 ++ containers/libreportal/frontend/js/spa.js | 44 +++++++++++- .../libreportal/frontend/kernel/lifecycle.js | 68 +++++++++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 containers/libreportal/frontend/features/backup/index.js create mode 100644 containers/libreportal/frontend/kernel/lifecycle.js diff --git a/containers/libreportal/frontend/features/backup/index.js b/containers/libreportal/frontend/features/backup/index.js new file mode 100644 index 0000000..b80f39b --- /dev/null +++ b/containers/libreportal/frontend/features/backup/index.js @@ -0,0 +1,41 @@ +// features/backup/index.js โ€” Backup Center as a self-contained feature module. +// +// FIRST page migrated to the feature-module contract (docs/frontend-modularization.md). +// The kernel drives mount()/unmount() for the /backup route instead of +// spa.js's handleBackup(). The heavy controller (backup-page.js, ~129KB) is +// still lazy-loaded on first mount, so cold-load cost is unchanged. +// +// Snap-out demo: deleting this folder removes the backup route's module +// registration; the manifest entry then falls back to the legacy handler +// (and, once handleBackup is retired, to the kernel's not-found route). The +// full decomposition of backup-page.js into per-tab modules is Phase 5. +LP.features.register({ + id: 'backup', + routes: ['/backup', '/backup*'], + // Controllers the feature needs; lazy-loaded on first mount (idempotent). + scripts: [ + '/js/components/backup/backup-page.js', + '/js/components/backup/backup-app-card.js', + ], + + async mount(ctx) { + await ctx.loadScripts(this.scripts); + const html = await ctx.loadFragment('/html/backup-content.html'); + ctx.setContent(html, 'Backups'); + if (typeof BackupPage === 'undefined') { + throw new Error('BackupPage controller failed to load'); + } + window.backupPage = new BackupPage(); + await window.backupPage.init(); + }, + + async unmount() { + // Best-effort teardown. BackupPage self-guards stale work via + // (window.backupPage === this), so nulling the global neutralises any + // pending task-refresh repaint; we also drop its coordinator registration. + // A proper dispose() (removing the leaked document listeners) lands with + // the Phase 5 backup decomposition. + try { window.taskRefresh && window.taskRefresh.unregister && window.taskRefresh.unregister('backups'); } catch (_) {} + window.backupPage = null; + }, +}); diff --git a/containers/libreportal/frontend/index.html b/containers/libreportal/frontend/index.html index 4980170..3f1890d 100755 --- a/containers/libreportal/frontend/index.html +++ b/containers/libreportal/frontend/index.html @@ -108,6 +108,10 @@ loads the page manifest; spa.js consults it for routing. See docs/frontend-modularization.md. --> + + +