refactor: enforce typed frontend runtime boundaries
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
-->
|
||||
|
||||
# Frontend architecture
|
||||
|
||||
The HTTP frontend is a strict TypeScript application built with esbuild. Rust
|
||||
embeds deterministic JavaScript output from `assets/web/generated`; Cargo does
|
||||
not run Node.js or contact the network.
|
||||
|
||||
## Runtime graph
|
||||
|
||||
`frontend/src/bootstrap.ts` is the only first-party script referenced by the
|
||||
HTML document. Its imports establish startup order for WebGL support, shared UI
|
||||
services, decoder dispatch, the local Leaflet AIS adapter, and the application
|
||||
coordinator. Leaflet and the Opus decoder remain isolated vendored scripts.
|
||||
|
||||
Feature entries under `frontend/src/plugins` are ESM bundles. The typed plugin
|
||||
loader imports them by feature group and keeps expensive map, scheduling, and
|
||||
decoder behavior lazy. Shared code is emitted as content-hashed chunks. The
|
||||
decode-history worker is an independent entry compiled against Web Worker
|
||||
globals.
|
||||
|
||||
Dependencies point from application and feature code toward `core` and `api`.
|
||||
`api/generated.ts` contains Rust wire formats; `api/client.ts` and focused
|
||||
parsers validate untrusted HTTP, SSE, WebSocket, and worker data before it is
|
||||
used as typed application state.
|
||||
|
||||
## Browser host contract
|
||||
|
||||
Separate lazy bundles cannot share module instances with the stable application
|
||||
entry, so they use three intentional host namespaces:
|
||||
|
||||
| Global | Purpose | Mutation policy |
|
||||
| --- | --- | --- |
|
||||
| `window.trx` | Application state, core services, and feature registrations | The root is frozen; lazy features may register only their documented `modules.*` service. |
|
||||
| `window.trxPluginRuntime` | Typed decoder registration and message dispatch | Runtime object is installed once; plugins register lifecycle handlers through its API. |
|
||||
| `window.trxUi` | Notifications, confirmations, tab accessibility, and control presentation | Installed once by `ui-core.ts`; consumers call methods but do not replace them. |
|
||||
|
||||
The WebGL adapter exposes `createTrxWebGlRenderer`, `trxParseCssColor`,
|
||||
`trxHslToRgba`, and `trxClearCssColorCache` for the application bundle. Leaflet
|
||||
adds `L.TrxAisTrackSymbol` and `L.trxAisTrackSymbol` to the vendored Leaflet
|
||||
namespace.
|
||||
|
||||
The following transitional properties are explicitly part of the lazy-feature
|
||||
host contract and are declared in `app.ts`: `lastSpectrumData`, `lastFreqHz`,
|
||||
`currentBandwidthHz`, `ft8BaseHz`, `getDecodeHistoryRetentionMs`,
|
||||
`applyDecodeHistoryRetention`, `getDecodeRigMeta`, `renderRdsOverlays`,
|
||||
`buildAisVesselUrl`, `trxScheduleUiFrameJob`,
|
||||
`takeSchedulerControlForDecoderDisable`, `navigateToTab`, `_syncRecorderState`,
|
||||
and `refreshRdsUi`. Optional callbacks owned by lazy features are
|
||||
`refreshCwTonePicker`, `updateFt8RfDisplay`, `clearSatPredictionDom`,
|
||||
`syncWefaxToggle`, `updateAisBar`, `updateVdesBar`, `updateAprsBar`,
|
||||
`updateFt8Bar`, `updateSatLiveState`, `applyCwAutoUi`, and
|
||||
`applyCwAutoUiFromServer`.
|
||||
|
||||
This list is closed: new standalone mutable `window` properties are not an
|
||||
accepted integration mechanism. Extend an existing typed service or introduce
|
||||
an imported interface instead. Removing transitional properties as feature
|
||||
boundaries become directly importable remains preferable.
|
||||
|
||||
## Build and verification
|
||||
|
||||
The generated directory is removed before every build, preventing orphaned
|
||||
compatibility bundles. Stable feature entry names are allowlisted by the Rust
|
||||
asset manifest; shared chunks use content hashes. The generic Rust handler
|
||||
rejects unknown names and unsupported MIME types and serves embedded assets
|
||||
with compression, ETags, and immutable caching.
|
||||
|
||||
CI installs from `package-lock.json`, caches only npm downloads, type-checks the
|
||||
window and worker environments separately, lints, runs unit and DOM tests,
|
||||
starts the application in Chromium, regenerates Rust contracts and bundles,
|
||||
checks for drift, and runs REUSE validation after generation.
|
||||
|
||||
See `frontend/src/README.md` for local commands and
|
||||
`docs/ts-migration-plan.md` for the migration decisions and completion gates.
|
||||
Reference in New Issue
Block a user