Skip to content

refactor(core): invoke media methods via callProp#1695

Closed
luwes wants to merge 1 commit into
mainfrom
refactor/media-call-prop
Closed

refactor(core): invoke media methods via callProp#1695
luwes wants to merge 1 commit into
mainfrom
refactor/media-call-prop

Conversation

@luwes

@luwes luwes commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Fix for feedback from #1661

Summary

Media methods (play, pause, load, canPlayType, addTextTrack) now invoke through the owner directly instead of reading a function prop and calling it detached. This removes the need to bind on every access — and the referential-stability cache that bind required — since a function reference is never handed out.

Changes

  • Add callProp(host, prop, ...args) to resolve the owning component/target and invoke the method with the owner as this, returning undefined when no owner exposes it.
  • Simplify getProp to return the raw owner value (no isFunction branch, no bind).
  • Route the host's function-prop accessors through callProp.
Why not cache the bound function?

Every consumer invokes immediately and discards the function, so no caller observes referential identity. The bind only ever existed to fix this on a detached call. Resolving and invoking in one step makes the cache unnecessary. callProp is typed against the concrete TargetLike constraint so Parameters/ReturnType inference resolves inside the generic host.

Testing

Covered by utils.test.ts (callProp receiver/return/no-owner) and existing media-host.test.ts. pnpm -F @videojs/core build and the core typecheck pass.


Note

Medium Risk
Touches core playback/control delegation (play, pause, etc.) where component overrides must keep correct this; behavior is intended to be equivalent but is on a sensitive path.

Overview
Media host methods no longer pull detached function references from getProp and call them without the correct receiver. callProp resolves the owning component override or attached target and invokes the method with that owner as this.

getProp now returns the raw property value only (no bind / function branch). play, pause, load, canPlayType, and addTextTrack on HTMLMediaElementHost route through callProp, with the same fallbacks when nothing is attached (e.g. rejected play). callProp is re-exported from the media host module.

Adds utils.test.ts covering getProp and callProp (receiver, return value, missing owner). Minor addComponent naming/comments only.

Reviewed by Cursor Bugbot for commit 9b2f997. Bugbot is set up for automated code reviews on this repo. Configure here.

@netlify

netlify Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit 9b2f997
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6a31e1f220a80c0008ce1511
😎 Deploy Preview https://deploy-preview-1695--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment Jun 16, 2026 11:53pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Size
/video (default) 41.80 kB
/video (default + hls) 181.34 kB
/video (minimal) 41.46 kB
/video (minimal + hls) 180.99 kB
/audio (default) 35.62 kB
/audio (minimal) 32.88 kB
/background 4.22 kB
Media (9)
Entry Size
/media/background-video 1.07 kB
/media/container 1.72 kB
/media/dash-video 242.71 kB
/media/hls-video 141.01 kB
/media/mux-audio 163.70 kB
/media/mux-video 163.51 kB
/media/native-hls-video 8.97 kB
/media/simple-hls-audio-only 16.07 kB
/media/simple-hls-video 17.88 kB
Players (5)
Entry Size
/video/player 7.61 kB
/audio/player 5.39 kB
/background/player 3.92 kB
/live-video/player 7.63 kB
/live-audio/player 5.40 kB
Skins (30)
Entry Type Size
/video/minimal-skin.css css 5.23 kB
/video/skin.css css 5.19 kB
/video/minimal-skin js 41.46 kB
/video/minimal-skin.tailwind js 41.95 kB
/video/skin js 41.78 kB
/video/skin.tailwind js 42.21 kB
/audio/minimal-skin.css css 3.45 kB
/audio/skin.css css 3.36 kB
/audio/minimal-skin js 32.92 kB
/audio/minimal-skin.tailwind js 33.22 kB
/audio/skin js 35.70 kB
/audio/skin.tailwind js 36.02 kB
/background/skin.css css 133 B
/background/skin js 1.16 kB
/live-video/minimal-skin.css css 5.23 kB
/live-video/skin.css css 5.19 kB
/live-video/minimal-skin js 40.88 kB
/live-video/minimal-skin.tailwind js 41.25 kB
/live-video/skin js 40.86 kB
/live-video/skin.tailwind js 41.13 kB
/live-audio/minimal-skin.css css 3.45 kB
/live-audio/skin.css css 3.36 kB
/live-audio/minimal-skin js 27.17 kB
/live-audio/minimal-skin.tailwind js 26.64 kB
/live-audio/skin js 29.61 kB
/live-audio/skin.tailwind js 29.19 kB
/global.css css 176 B
/shared.css css 88 B
/tailwind.css css 228 B
/skin-element js 1.37 kB
UI Components (37)
Entry Size
/ui/airplay-button 2.92 kB
/ui/alert-dialog 1.27 kB
/ui/alert-dialog-close 558 B
/ui/alert-dialog-description 448 B
/ui/alert-dialog-title 450 B
/ui/buffering-indicator 2.79 kB
/ui/captions-button 2.96 kB
/ui/captions-radio-group 2.21 kB
/ui/cast-button 2.87 kB
/ui/compounds 8.22 kB
/ui/controls 2.19 kB
/ui/error-dialog 3.25 kB
/ui/fullscreen-button 2.91 kB
/ui/hotkey 2.04 kB
/ui/menu 5.38 kB
/ui/mute-button 2.96 kB
/ui/pip-button 2.88 kB
/ui/play-button 2.88 kB
/ui/playback-rate-button 2.93 kB
/ui/playback-rate-radio-group 2.18 kB
/ui/popover 2.10 kB
/ui/poster 2.59 kB
/ui/seek-button 2.87 kB
/ui/seek-indicator 3.76 kB
/ui/seek-indicator-value 241 B
/ui/slider 1.50 kB
/ui/status-announcer 3.39 kB
/ui/status-indicator 3.48 kB
/ui/status-indicator-value 272 B
/ui/thumbnail 3.16 kB
/ui/time 1.99 kB
/ui/time-slider 2.90 kB
/ui/tooltip 2.23 kB
/ui/volume-indicator 3.67 kB
/ui/volume-indicator-fill 222 B
/ui/volume-indicator-value 222 B
/ui/volume-slider 3.67 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react — no changes
Presets (7)
Entry Size
/video (default) 34.72 kB
/video (default + hls) 172.93 kB
/video (minimal) 34.77 kB
/video (minimal + hls) 173.06 kB
/audio (default) 28.43 kB
/audio (minimal) 28.51 kB
/background 754 B
Media (8)
Entry Size
/media/background-video 575 B
/media/dash-video 241.41 kB
/media/hls-video 139.66 kB
/media/mux-audio 162.22 kB
/media/mux-video 162.12 kB
/media/native-hls-video 7.43 kB
/media/simple-hls-audio-only 14.61 kB
/media/simple-hls-video 16.37 kB
Skins (27)
Entry Type Size
/tailwind.css css 228 B
/video/minimal-skin.css css 5.14 kB
/video/skin.css css 5.10 kB
/video/minimal-skin js 34.69 kB
/video/minimal-skin.tailwind js 40.13 kB
/video/skin js 34.63 kB
/video/skin.tailwind js 39.99 kB
/audio/minimal-skin.css css 3.32 kB
/audio/skin.css css 3.23 kB
/audio/minimal-skin js 28.45 kB
/audio/minimal-skin.tailwind js 28.91 kB
/audio/skin js 28.36 kB
/audio/skin.tailwind js 31.97 kB
/background/skin.css css 90 B
/background/skin js 272 B
/live-video/minimal-skin.css css 5.14 kB
/live-video/skin.css css 5.10 kB
/live-video/minimal-skin js 30.93 kB
/live-video/minimal-skin.tailwind js 36.15 kB
/live-video/skin js 30.88 kB
/live-video/skin.tailwind js 36.14 kB
/live-audio/minimal-skin.css css 3.32 kB
/live-audio/skin.css css 3.23 kB
/live-audio/minimal-skin js 20.94 kB
/live-audio/minimal-skin.tailwind js 23.71 kB
/live-audio/skin js 20.96 kB
/live-audio/skin.tailwind js 23.77 kB
UI Components (31)
Entry Size
/ui/airplay-button 2.87 kB
/ui/alert-dialog 1.21 kB
/ui/buffering-indicator 2.60 kB
/ui/captions-button 2.86 kB
/ui/captions-radio-group 2.58 kB
/ui/cast-button 2.88 kB
/ui/controls 2.52 kB
/ui/error-dialog 2.49 kB
/ui/fullscreen-button 2.83 kB
/ui/gesture 2.05 kB
/ui/hotkey 2.65 kB
/ui/live-button 2.78 kB
/ui/menu 5.53 kB
/ui/mute-button 2.94 kB
/ui/pip-button 2.88 kB
/ui/play-button 2.89 kB
/ui/playback-rate 2.54 kB
/ui/playback-rate-button 2.83 kB
/ui/popover 2.42 kB
/ui/poster 2.43 kB
/ui/seek-button 2.91 kB
/ui/seek-indicator 2.06 kB
/ui/slider 4.38 kB
/ui/status-announcer 1.85 kB
/ui/status-indicator 1.96 kB
/ui/thumbnail 2.76 kB
/ui/time 2.66 kB
/ui/time-slider 3.98 kB
/ui/tooltip 2.63 kB
/ui/volume-indicator 2.05 kB
/ui/volume-slider 3.40 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core — no changes
Entries (11)
Entry Size
. 7.94 kB
/dom 16.40 kB
/dom/media/custom-media-element 2.00 kB
/dom/media/dash 236.83 kB
/dom/media/google-cast 4.04 kB
/dom/media/hls 135.62 kB
/dom/media/media-host 1.33 kB
/dom/media/mux 151.26 kB
/dom/media/native-hls 3.04 kB
/dom/media/simple-hls 15.75 kB
/dom/media/simple-hls-audio-only 13.94 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Size
. 996 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Size
. 1.39 kB
/html 696 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (10)
Entry Size
/array 104 B
/dom 2.22 kB
/events 319 B
/function 327 B
/object 275 B
/predicate 265 B
/string 192 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (4)
Entry Size
. 4.45 kB
/dom 6.33 kB
/hls 14.61 kB
/background-looping-video 12.29 kB

ℹ️ How to interpret

All sizes are standalone totals (minified + brotli).

Icon Meaning
No change
🔺 Increased ≤ 10%
🔴 Increased > 10%
🔽 Decreased
🆕 New (no baseline)

Run pnpm size locally to check current sizes.

@luwes luwes closed this Jun 17, 2026
luwes added a commit that referenced this pull request Jun 17, 2026
Split media utils into components/config modules and rework how
component config is exposed on the host.

- Component config is no longer bridged via Object.defineProperty on the
  config object. The getter enumerates registered components live under
  their configKey; the setter routes matching keys onto the component.
- Assigning a new config object now resets the free-form host/engine bag
  (start-fresh intent) instead of merging. Component state is preserved
  and only overwritten per-key by the incoming config.
- Reading config returns a fresh object, so mutating the result no longer
  writes through to components; use the setter instead.

Stacked on #1695.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant