Skip to content

fix(spf): fix async teardown leaks and recreate engine on src change#841

Merged
cjpillsbury merged 1 commit intomainfrom
fix/spf-cleanup-teardown
Mar 10, 2026
Merged

fix(spf): fix async teardown leaks and recreate engine on src change#841
cjpillsbury merged 1 commit intomainfrom
fix/spf-cleanup-teardown

Conversation

@cjpillsbury
Copy link
Copy Markdown
Collaborator

Audit of playback engine orchestrations found several async tasks that could continue running (and mutating DOM/state) after destroy() was called.

Fix teardown leaks:

  • setupMediaSource: abort waitForSourceOpen via AbortController on destroy
  • updateDuration: skip mediaSource.duration mutation if destroyed after await
  • endOfStream: skip runEvaluate if destroyed (guards mediaSource.endOfStream)
  • loadTextTrackCues: abort in-flight VTT fetch on cleanup (controller already existed but wasn't called from the returned cleanup function)

Recreate engine on src change:

  • SpfMedia.src setter now destroys the current engine and creates a fresh one instead of patching presentation on the existing engine. This ensures all state, SourceBuffers, and in-flight requests from the previous source are fully torn down before the next source begins loading — matching the browser's own load algorithm semantics. The media element reference is preserved and re-applied to the new engine automatically.

Audit of playback engine orchestrations found several async tasks that
could continue running (and mutating DOM/state) after destroy() was called.

Fix teardown leaks:
- setupMediaSource: abort waitForSourceOpen via AbortController on destroy
- updateDuration: skip mediaSource.duration mutation if destroyed after await
- endOfStream: skip runEvaluate if destroyed (guards mediaSource.endOfStream)
- loadTextTrackCues: abort in-flight VTT fetch on cleanup (controller already
  existed but wasn't called from the returned cleanup function)

Recreate engine on src change:
- SpfMedia.src setter now destroys the current engine and creates a fresh one
  instead of patching presentation on the existing engine. This ensures all
  state, SourceBuffers, and in-flight requests from the previous source are
  fully torn down before the next source begins loading — matching the
  browser's own load algorithm semantics. The media element reference is
  preserved and re-applied to the new engine automatically.
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 10, 2026

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

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment Mar 10, 2026 2:42pm

Request Review

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 10, 2026

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit cc8655e
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/69b02def13baa100083305e9
😎 Deploy Preview https://deploy-preview-841--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@cjpillsbury cjpillsbury merged commit f50d509 into main Mar 10, 2026
9 of 10 checks passed
@cjpillsbury cjpillsbury deleted the fix/spf-cleanup-teardown branch March 10, 2026 14:43
@github-actions github-actions bot mentioned this pull request Mar 10, 2026
@github-actions
Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html

(no changes)

Presets (7)
Entry Size
/video (default) 22.95 kB
/video (default + hls) 153.33 kB
/video (minimal) 22.81 kB
/video (minimal + hls) 153.26 kB
/audio (default) 21.17 kB
/audio (minimal) 21.15 kB
/background 6.36 kB
Media (4)
Entry Size
/media/background-video 652 B
/media/container 1.86 kB
/media/hls-video 131.32 kB
/media/simple-hls-video 11.57 kB
Players (3)
Entry Size
/video/player 6.22 kB
/audio/player 6.21 kB
/background/player 6.21 kB
Skins (14)
Entry Type Size
/video/minimal-skin.css css 2.74 kB
/video/skin.css css 2.79 kB
/video/minimal-skin js 22.23 kB
/video/minimal-skin.tailwind js 21.48 kB
/video/skin js 22.40 kB
/video/skin.tailwind js 21.52 kB
/audio/minimal-skin.css css 2.17 kB
/audio/skin.css css 2.19 kB
/audio/minimal-skin js 20.58 kB
/audio/minimal-skin.tailwind js 19.71 kB
/audio/skin js 20.62 kB
/audio/skin.tailwind js 19.89 kB
/background/skin.css css 124 B
/background/skin js 1009 B
UI Components (21)
Entry Size
/ui/alert-dialog 2.05 kB
/ui/alert-dialog-close 1.22 kB
/ui/alert-dialog-description 1.16 kB
/ui/alert-dialog-title 1.17 kB
/ui/buffering-indicator 1.71 kB
/ui/captions-button 1.82 kB
/ui/controls 1.79 kB
/ui/fullscreen-button 1.77 kB
/ui/mute-button 1.79 kB
/ui/pip-button 1.77 kB
/ui/play-button 1.77 kB
/ui/playback-rate-button 1.80 kB
/ui/popover 3.06 kB
/ui/poster 1.66 kB
/ui/seek-button 1.81 kB
/ui/slider 2.22 kB
/ui/thumbnail 2.08 kB
/ui/time 1.85 kB
/ui/time-slider 2.92 kB
/ui/tooltip 2.42 kB
/ui/volume-slider 2.19 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react

(no changes)

Presets (7)
Entry Size
/video (default) 16.68 kB
/video (default + hls) 147.49 kB
/video (minimal) 16.72 kB
/video (minimal + hls) 147.54 kB
/audio (default) 14.39 kB
/audio (minimal) 14.41 kB
/background 3.14 kB
Media (3)
Entry Size
/media/background-video 539 B
/media/hls-video 131.60 kB
/media/simple-hls-video 11.95 kB
Skins (14)
Entry Type Size
/video/minimal-skin.css css 2.74 kB
/video/skin.css css 2.79 kB
/video/minimal-skin js 16.61 kB
/video/minimal-skin.tailwind js 19.14 kB
/video/skin js 16.57 kB
/video/skin.tailwind js 19.16 kB
/audio/minimal-skin.css css 2.17 kB
/audio/skin.css css 2.19 kB
/audio/minimal-skin js 14.34 kB
/audio/minimal-skin.tailwind js 16.13 kB
/audio/skin js 14.27 kB
/audio/skin.tailwind js 16.32 kB
/background/skin.css css 90 B
/background/skin js 272 B
UI Components (17)
Entry Size
/ui/alert-dialog 2.70 kB
/ui/buffering-indicator 2.20 kB
/ui/captions-button 2.26 kB
/ui/controls 2.19 kB
/ui/fullscreen-button 2.28 kB
/ui/mute-button 2.23 kB
/ui/pip-button 2.26 kB
/ui/play-button 2.25 kB
/ui/playback-rate-button 2.24 kB
/ui/popover 3.10 kB
/ui/poster 2.05 kB
/ui/seek-button 2.25 kB
/ui/slider 3.09 kB
/ui/time 2.36 kB
/ui/time-slider 3.24 kB
/ui/tooltip 3.20 kB
/ui/volume-slider 3.08 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core

(no changes)

Entries (5)
Entry Size
. 4.78 kB
/dom 8.02 kB
/dom/media/custom-media-element 1.77 kB
/dom/media/hls 131.18 kB
/dom/media/simple-hls 11.48 kB

🏷️ @videojs/element

(no changes)

Entries (2)
Entry Size
. 999 B
/context 936 B

📦 @videojs/store

(no changes)

Entries (3)
Entry Size
. 1.32 kB
/html 700 B
/react 360 B

🔧 @videojs/utils

(no changes)

Entries (10)
Entry Size
/array 104 B
/dom 1003 B
/events 227 B
/function 261 B
/object 119 B
/predicate 265 B
/string 148 B
/style 190 B
/time 478 B
/number 158 B

📦 @videojs/spf

(no changes)

Entries (3)
Entry Size
. 40 B
/dom 9.69 kB
/playback-engine 9.56 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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant