mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
refactor(media)!: extract media package from core (#1879)
This commit is contained in:
@@ -14,21 +14,21 @@ Treating every media target as a complete `HTMLMediaElement` coupled player stat
|
||||
## Decisions
|
||||
|
||||
- Define small capabilities for playback, source, seeking, volume, tracks, presentation modes, and related events instead of one mandatory browser-shaped contract.
|
||||
- Keep core contracts structural and DOM-free. Minimal event, target, range, and track shapes allow browser objects to satisfy them without making browser types the abstraction boundary.
|
||||
- Keep media contracts structural and DOM-free. Minimal event, target, range, and track shapes allow browser objects to satisfy them without making browser types the abstraction boundary.
|
||||
- Require a feature to narrow to the capability it needs. The base player target cannot imply support for optional media behavior.
|
||||
- Put native-element forwarding in DOM host classes, where platform behavior belongs, rather than in the core contract.
|
||||
- Put native-element forwarding in DOM host classes, where platform behavior belongs, rather than in the shared contract.
|
||||
- Expose engine ownership through `MediaEngineHost`; keep engine-specific state off the common media surface.
|
||||
- Make engine destruction asynchronous so source or configuration replacement can wait for network and MediaSource cleanup.
|
||||
- Keep HTML custom elements as adapters over core media hosts rather than a second media hierarchy.
|
||||
- Keep HTML custom elements as adapters over media hosts rather than a second media hierarchy.
|
||||
|
||||
## Consequences
|
||||
|
||||
Custom media can implement only the capabilities it supports, store features reveal their real dependencies, and non-DOM adapters can share the same core contracts. The cost is explicit capability checks and more interfaces, which is preferable to an implicit, oversized platform contract.
|
||||
Custom media can implement only the capabilities it supports, store features reveal their real dependencies, and non-DOM adapters can share the same media contracts. The cost is explicit capability checks and more interfaces, which is preferable to an implicit, oversized platform contract.
|
||||
|
||||
## Current sources of truth
|
||||
|
||||
- Contracts and type guards: `packages/core/src/core/media/`
|
||||
- Browser hosts and engine-backed media: `packages/core/src/dom/media/`
|
||||
- Contracts and type guards: `packages/media/src/core/`
|
||||
- Browser hosts and engine-backed media: `packages/media/src/dom/`
|
||||
- HTML element adapters: `packages/html/src/media/`
|
||||
- Player feature consumers and tests: `packages/core/src/dom/store/features/`
|
||||
- Public exports and generated API reference
|
||||
|
||||
@@ -33,7 +33,7 @@ the mixin.
|
||||
| Phase | What | Notes |
|
||||
|---|---|---|
|
||||
| Writable signal refs via `onSignalsReady` | `shareSignals` captures `Signal<T>` / `ReadonlySignal<T>` refs into a consumer-supplied callback at setup time. Generic over composition shape (`makeShareSignals<S, C>()`) | Per-slot read/write intent is expressed at the use site (callers type captured refs as `Signal<T>` or `ReadonlySignal<T>`). Composed last in the engine so initial state writes are visible to the consumer |
|
||||
| Mixin adapter pattern | `SimpleHlsMediaMixin` is the canonical consumer: function-of-base-class structure (mix into any base), captures refs once in `onSignalsReady`, exposes a WHATWG HTMLMediaElement-shaped API mapping each setter/method to engine writes | Downstream use: `class SimpleHlsMedia extends SimpleHlsMediaMixin(HTMLVideoElementHost) {}` in `packages/core/src/dom/media/simple-hls/` |
|
||||
| Mixin adapter pattern | `SimpleHlsMediaMixin` is the canonical consumer: function-of-base-class structure (mix into any base), captures refs once in `onSignalsReady`, exposes a WHATWG HTMLMediaElement-shaped API mapping each setter/method to engine writes | Downstream use: `class SimpleHlsMedia extends SimpleHlsMediaMixin(HTMLVideoElementHost) {}` in `packages/media/src/dom/simple-hls/` |
|
||||
| Media element binding | `attach(el)` writes `context.mediaElement`; `detach()` clears it. **Engine persists across attach/detach cycles** — only `src` reassignment or explicit `destroy()` tears it down | Re-attach to a different element is supported. The engine is the durable state holder; `mediaElement` is a context slot |
|
||||
| Source assignment via in-place recycling | Adapter's `set src` overwrites `state.presentation` on its single recycled engine (`{ url }`, or `undefined` for empty src). Media element + engine-wide preload persist; no engine recreation, no signal re-capture | Drives the engine's in-place source-replacement cascade — see [source-replacement.md](./source-replacement.md). (The adapter previously destroyed + recreated the engine per assignment.) |
|
||||
| Preload reflection | `set preload(value)` writes W3C values to `state.preload`; clearing (`preload = ''`) doesn't patch the current engine but is re-applied on the next src change. Pre-attach src + preload combinations are supported | Extended preload values flow through state but don't reach the DOM (per [`preload-modes`](./preload-modes.md)'s sticky-extended-values semantics) |
|
||||
@@ -105,7 +105,7 @@ return createComposition(
|
||||
| `set preload(value)` | `state.preload.set(value)` (W3C values only; pre-empties stay engine-local) |
|
||||
| `play()` | `state.loadActivated.set(true)` → native `play()` with `loadstart` retry on "no supported sources" |
|
||||
|
||||
**Downstream consumer:** `packages/core/src/dom/media/simple-hls/index.ts`:
|
||||
**Downstream consumer:** `packages/media/src/dom/simple-hls/media.ts`:
|
||||
|
||||
```ts
|
||||
export class SimpleHlsMedia extends SimpleHlsMediaMixin(HTMLVideoElementHost) {}
|
||||
@@ -148,7 +148,7 @@ each `set src`).
|
||||
- `packages/spf/src/core/composition/tests/share-signals.test.ts`
|
||||
— the behavior itself
|
||||
- **Downstream usage:**
|
||||
- `packages/core/src/dom/media/simple-hls/index.ts` —
|
||||
- `packages/media/src/dom/simple-hls/media.ts` —
|
||||
`SimpleHlsMedia` consumer
|
||||
- **Walkthrough:**
|
||||
- `packages/spf/docs/hls-engine.md` Stage 10 — high-level coverage
|
||||
@@ -220,5 +220,5 @@ each `set src`).
|
||||
- [conventions/signals.md](../conventions/signals.md) — per-slot
|
||||
`Signal<T>` / `ReadonlySignal<T>` intent (relevant for how consumers
|
||||
type captured refs at the use site)
|
||||
- `packages/core/src/dom/media/simple-hls/index.ts` — canonical
|
||||
- `packages/media/src/dom/simple-hls/media.ts` — canonical
|
||||
downstream consumer
|
||||
|
||||
@@ -299,19 +299,19 @@ parallel to the existing `simple-hls-video` pair.
|
||||
Public re-export: `@videojs/spf/hls` — all of the above ship via
|
||||
`packages/spf/src/playback/engines/hls/index.ts`.
|
||||
|
||||
**Core — media wrapper** (`packages/core/src/dom/media/simple-hls-audio-only/`):
|
||||
**Core — media wrapper** (`packages/media/src/dom/simple-hls-audio-only/`):
|
||||
|
||||
| Export | File | Purpose |
|
||||
|---|---|---|
|
||||
| `SimpleHlsAudioOnlyMedia` | `index.ts` | Applies `SimpleHlsAudioOnlyMediaMixin` to `HTMLAudioElementHost` (audio host, not video — symmetric with `mux-audio`) |
|
||||
|
||||
Public re-export: `@videojs/core/dom/media/simple-hls-audio-only`.
|
||||
Public re-export: `@videojs/media/dom/simple-hls-audio-only`.
|
||||
|
||||
**HTML — custom element** (`packages/html/src/media/simple-hls-audio-only/`):
|
||||
|
||||
| Export | File | Purpose |
|
||||
|---|---|---|
|
||||
| `SimpleHlsAudioOnly` | `media/simple-hls-audio-only/index.ts` | Applies `MediaAttachMixin` + `CustomMediaElement('audio', SimpleHlsAudioOnlyMedia)` |
|
||||
| `SimpleHlsAudioOnly` | `media/simple-hls-audio-only/media.ts` | Applies `MediaAttachMixin` + `CustomMediaElement('audio', SimpleHlsAudioOnlyMedia)` |
|
||||
| `SimpleHlsAudioOnlyElement` (tag `simple-hls-audio-only`) | `define/media/simple-hls-audio-only.ts` | Custom-element definition; registers `<simple-hls-audio-only>` via `safeDefine` |
|
||||
|
||||
CDN entry: `packages/html/src/cdn/media/simple-hls-audio-only.ts` →
|
||||
@@ -415,8 +415,8 @@ configuration drives end-of-stream correctly with no per-type changes.
|
||||
- [`packages/spf/src/playback/engines/hls/adapter-audio-only.ts`](../../../../packages/spf/src/playback/engines/hls/adapter-audio-only.ts) — Phase 1 adapter
|
||||
- [`packages/spf/src/playback/engines/hls/tests/engine-audio-only.test.ts`](../../../../packages/spf/src/playback/engines/hls/tests/engine-audio-only.test.ts) — Phase 1 engine integration tests
|
||||
- [`packages/spf/src/playback/engines/hls/tests/adapter-audio-only.test.ts`](../../../../packages/spf/src/playback/engines/hls/tests/adapter-audio-only.test.ts) — Phase 1 adapter tests
|
||||
- [`packages/core/src/dom/media/simple-hls-audio-only/index.ts`](../../../../packages/core/src/dom/media/simple-hls-audio-only/index.ts) — Phase 1 core media wrapper
|
||||
- [`packages/html/src/media/simple-hls-audio-only/index.ts`](../../../../packages/html/src/media/simple-hls-audio-only/index.ts) — Phase 1 HTML custom element
|
||||
- [`packages/react/src/media/simple-hls-audio-only/index.tsx`](../../../../packages/react/src/media/simple-hls-audio-only/index.tsx) — Phase 1 React component
|
||||
- [`packages/media/src/dom/simple-hls-audio-only/media.ts`](../../../../packages/media/src/dom/simple-hls-audio-only/media.ts) — Phase 1 media wrapper
|
||||
- [`packages/html/src/media/simple-hls-audio-only/media.ts`](../../../../packages/html/src/media/simple-hls-audio-only/media.ts) — Phase 1 HTML custom element
|
||||
- [`packages/react/src/media/simple-hls-audio-only/media.tsx`](../../../../packages/react/src/media/simple-hls-audio-only/media.tsx) — Phase 1 React component
|
||||
- [`apps/sandbox/templates/html-simple-hls-audio-only/`](../../../../apps/sandbox/templates/html-simple-hls-audio-only/) — Phase 1 HTML sandbox demo template
|
||||
- [`apps/sandbox/templates/react-simple-hls-audio-only/`](../../../../apps/sandbox/templates/react-simple-hls-audio-only/) — Phase 1 React sandbox demo template
|
||||
|
||||
Reference in New Issue
Block a user