Skip to content

fix(site): restore react demos for ssr-safe media elements - #1867

Merged
decepulis merged 3 commits into
mainfrom
fix/restore-react-media-demos
Jul 24, 2026
Merged

fix(site): restore react demos for ssr-safe media elements#1867
decepulis merged 3 commits into
mainfrom
fix/restore-react-media-demos

Conversation

@decepulis

@decepulis decepulis commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Refs #1343

Summary

The React live demos on the seven media element reference pages were replaced with source-only tabs as a workaround for #1343. Only dashjs actually breaks SSR — hls.js and mux-embed both import cleanly in Node — so the six pages that were never affected go back to the standard demo pattern. dash-video is left as-is.

Changes

  • Restored live React demos on hlsjs-video, native-hls-video, simple-hls-video, simple-hls-audio-only, mux-video, and mux-audio using the usual <Demo> + client:idle pattern.
  • dash-video is unchanged and keeps its source-only tabs until dashjs can be loaded lazily in core.
Why dash is the only page still blocked

Upstream dash.js#4929 shipped in dashjs 5.2.0 and made MediaPlayerFactory SSR-safe, but that only covered half the problem. dashjs statically bundles imsc, whose html.js reads window.getComputedStyle(document.documentElement) at module scope (three times, for ruby/text-emphasis feature detection). So import * as dashjs from 'dashjs' still throws in Node. imsc@1.1.5 is the latest release and there's no open issue for this in either repo.

A client:only directive is not a fix either: Astro still emits a static import for the island, so the module is evaluated during prerender and the build fails with window is not defined. Working around it in the docs site requires routing the demo through lazy(() => import(...)) so only a dynamic import lands on the server graph — which is more machinery than one demo justifies. The real fix belongs in @videojs/core, lazy-loading dashjs in the host class lifecycle, which is what #1343 tracks.

Testing

  • pnpm -F site exec astro check --minimumSeverity warning — 0 errors, 0 warnings
  • pnpm typecheck, pnpm -F site test (512 tests), pnpm check:workspace
  • pnpm -F site build — all 7 React and 7 HTML media reference pages prerender
  • Confirmed hls.js and mux-embed import cleanly in bare Node, and that the six restored pages server-render their media element

One caveat for the reviewer: pnpm -F site build still fails on / with TypeError: Cannot read properties of undefined (reading 'data'). This reproduces on a clean origin/main, so it is pre-existing and unrelated to this PR — but CI here will not be green until it is fixed.

The live React demos on the media element reference pages were replaced
with source-only tabs as a workaround for #1343. Only dashjs actually
breaks SSR: hls.js and mux-embed both import cleanly in Node, so these
six pages can use the standard `<Demo>` + `client:idle` pattern again.
dashjs is the one media engine that still breaks SSR: it bundles imsc,
which reads `window.getComputedStyle` at module scope, so upstream's
MediaPlayerFactory fix in 5.2.0 only covered half the problem (#1343).

`client:only` alone is not enough — Astro still emits a static import for
the island, so the module is evaluated during prerender and the build
fails. Routing the demo through `lazy(() => import(...))` leaves only a
dynamic import on the server graph, which never executes. An
`aspect-video` wrapper reserves the demo's box so hydration doesn't shift
the page.
@netlify

netlify Bot commented Jul 24, 2026

Copy link
Copy Markdown

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit f5e8fb2
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6a63e3de9e6a57000846633d
😎 Deploy Preview https://deploy-preview-1867--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 Jul 24, 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 Jul 24, 2026 10:15pm

Request Review

Reverts a5ab6f7. The lazy-import wrapper needed to keep dashjs out of
the prerender was more machinery than a single demo justifies, so
dash-video keeps its source-only tabs until dashjs loads lazily in core.

Refs #1343
@github-actions

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Initial Lazy
/video (default) 51.12 kB 54.24 kB
/video (default + hls) 190.40 kB 54.24 kB
/video (minimal) 51.11 kB 54.24 kB
/video (minimal + hls) 190.57 kB 54.24 kB
/audio (default) 44.42 kB 54.24 kB
/audio (minimal) 41.63 kB 54.24 kB
/background 4.20 kB
Media (10)
Entry Initial
/media/background-video 1.14 kB
/media/container 1.71 kB
/media/dash-video 214.79 kB
/media/hlsjs-video 141.52 kB
/media/mux-audio 164.00 kB
/media/mux-video 163.70 kB
/media/native-hls-video 9.05 kB
/media/simple-hls-audio-only 17.19 kB
/media/simple-hls-video 18.69 kB
/media/vimeo-video 12.31 kB
Players (5)
Entry Initial
/video/player 8.22 kB
/audio/player 5.38 kB
/background/player 3.92 kB
/live-video/player 7.63 kB
/live-audio/player 5.39 kB
Skins (30)
Entry Type Initial Lazy
/video/minimal-skin.css css 5.70 kB
/video/skin.css css 5.65 kB
/video/minimal-skin js 51.10 kB 54.24 kB
/video/minimal-skin.tailwind js 51.87 kB 54.24 kB
/video/skin js 51.12 kB 54.24 kB
/video/skin.tailwind js 51.87 kB 54.24 kB
/audio/minimal-skin.css css 3.97 kB
/audio/skin.css css 3.86 kB
/audio/minimal-skin js 41.62 kB 54.24 kB
/audio/minimal-skin.tailwind js 42.20 kB 54.24 kB
/audio/skin js 44.42 kB 54.24 kB
/audio/skin.tailwind js 44.91 kB 54.24 kB
/background/skin.css css 133 B
/background/skin js 1.14 kB
/live-video/minimal-skin.css css 5.70 kB
/live-video/skin.css css 5.65 kB
/live-video/minimal-skin js 48.06 kB 54.24 kB
/live-video/minimal-skin.tailwind js 48.56 kB 54.24 kB
/live-video/skin js 49.60 kB 54.24 kB
/live-video/skin.tailwind js 50.22 kB 54.24 kB
/live-audio/minimal-skin.css css 3.97 kB
/live-audio/skin.css css 3.86 kB
/live-audio/minimal-skin js 33.99 kB 54.24 kB
/live-audio/minimal-skin.tailwind js 33.42 kB 54.24 kB
/live-audio/skin js 36.91 kB 54.24 kB
/live-audio/skin.tailwind js 36.40 kB 54.24 kB
/global.css css 183 B
/shared.css css 153 B
/tailwind.css css 161 B
/skin-element js 1.51 kB
UI Components (39)
Entry Initial
/ui/airplay-button 2.57 kB
/ui/alert-dialog 2.95 kB
/ui/alert-dialog-close 2.39 kB
/ui/alert-dialog-description 2.39 kB
/ui/alert-dialog-title 2.34 kB
/ui/audio-track-radio-group 3.00 kB
/ui/buffering-indicator 2.68 kB
/ui/captions-button 2.69 kB
/ui/captions-radio-group 3.05 kB
/ui/cast-button 2.62 kB
/ui/compounds 3.22 kB
/ui/controls 2.93 kB
/ui/error-dialog 2.94 kB
/ui/fullscreen-button 2.60 kB
/ui/hotkey 2.43 kB
/ui/menu 2.97 kB
/ui/mute-button 2.61 kB
/ui/pip-button 2.59 kB
/ui/play-button 2.60 kB
/ui/playback-rate-button 2.66 kB
/ui/playback-rate-radio-group 2.89 kB
/ui/popover 3.14 kB
/ui/poster 2.50 kB
/ui/quality-radio-group 3.03 kB
/ui/seek-button 2.63 kB
/ui/seek-indicator 2.75 kB
/ui/seek-indicator-value 528 B
/ui/slider 2.95 kB
/ui/status-announcer 2.54 kB
/ui/status-indicator 2.68 kB
/ui/status-indicator-value 528 B
/ui/thumbnail 2.64 kB
/ui/time 2.93 kB
/ui/time-slider 2.96 kB
/ui/tooltip 2.94 kB
/ui/volume-indicator 2.59 kB
/ui/volume-indicator-fill 464 B
/ui/volume-indicator-value 463 B
/ui/volume-slider 2.95 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react — no changes
Presets (7)
Entry Initial Lazy
/video (default) 40.75 kB 54.24 kB
/video (default + hls) 178.69 kB 54.24 kB
/video (minimal) 41.12 kB 54.24 kB
/video (minimal + hls) 179.40 kB 54.24 kB
/audio (default) 33.91 kB 54.24 kB
/audio (minimal) 33.96 kB 54.24 kB
/background 579 B
Media (9)
Entry Initial
/media/background-video 403 B
/media/dash-video 212.98 kB
/media/hlsjs-video 139.79 kB
/media/mux-audio 162.38 kB
/media/mux-video 162.41 kB
/media/native-hls-video 7.26 kB
/media/simple-hls-audio-only 15.39 kB
/media/simple-hls-video 16.96 kB
/media/vimeo-video 10.44 kB
Skins (27)
Entry Type Initial Lazy
/tailwind.css css 161 B
/video/minimal-skin.css css 5.55 kB
/video/skin.css css 5.52 kB
/video/minimal-skin js 40.98 kB 54.24 kB
/video/minimal-skin.tailwind js 47.11 kB 54.24 kB
/video/skin js 40.65 kB 54.24 kB
/video/skin.tailwind js 46.79 kB 54.24 kB
/audio/minimal-skin.css css 3.79 kB
/audio/skin.css css 3.68 kB
/audio/minimal-skin js 33.88 kB 54.24 kB
/audio/minimal-skin.tailwind js 36.11 kB 54.24 kB
/audio/skin js 33.86 kB 54.24 kB
/audio/skin.tailwind js 38.06 kB 54.24 kB
/background/skin.css css 90 B
/background/skin js 272 B
/live-video/minimal-skin.css css 5.55 kB
/live-video/skin.css css 5.52 kB
/live-video/minimal-skin js 35.43 kB 54.24 kB
/live-video/minimal-skin.tailwind js 41.46 kB 54.24 kB
/live-video/skin js 35.44 kB 54.24 kB
/live-video/skin.tailwind js 41.55 kB 54.24 kB
/live-audio/minimal-skin.css css 3.79 kB
/live-audio/skin.css css 3.68 kB
/live-audio/minimal-skin js 24.25 kB 54.24 kB
/live-audio/minimal-skin.tailwind js 27.42 kB 54.24 kB
/live-audio/skin js 24.31 kB 54.24 kB
/live-audio/skin.tailwind js 27.45 kB 54.24 kB
UI Components (33)
Entry Initial
/ui/airplay-button 2.49 kB
/ui/alert-dialog 2.66 kB
/ui/audio-track 2.30 kB
/ui/buffering-indicator 2.51 kB
/ui/captions-button 2.44 kB
/ui/captions-radio-group 2.28 kB
/ui/cast-button 2.44 kB
/ui/controls 2.48 kB
/ui/error-dialog 2.47 kB
/ui/fullscreen-button 2.46 kB
/ui/gesture 2.31 kB
/ui/hotkey 2.27 kB
/ui/live-button 2.37 kB
/ui/menu 2.60 kB
/ui/mute-button 2.42 kB
/ui/pip-button 2.43 kB
/ui/play-button 2.52 kB
/ui/playback-rate 2.46 kB
/ui/playback-rate-button 2.44 kB
/ui/popover 3.06 kB
/ui/poster 2.42 kB
/ui/quality 2.27 kB
/ui/seek-button 2.42 kB
/ui/seek-indicator 2.60 kB
/ui/slider 2.69 kB
/ui/status-announcer 2.34 kB
/ui/status-indicator 2.38 kB
/ui/thumbnail 2.43 kB
/ui/time 2.27 kB
/ui/time-slider 2.58 kB
/ui/tooltip 3.04 kB
/ui/volume-indicator 2.32 kB
/ui/volume-slider 2.57 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core — no changes
Entries (68)
Entry Initial Lazy
. 10.55 kB
/dom 17.70 kB
/dom/media/custom-media-element 2.09 kB
/dom/media/dash 208.97 kB
/dom/media/google-cast 4.03 kB
/dom/media/hls-js 135.87 kB
/dom/media/media-host 1.25 kB
/dom/media/media-played-ranges 576 B
/dom/media/mux 151.37 kB
/dom/media/native-hls 3.07 kB
/dom/media/simple-hls 16.48 kB
/dom/media/simple-hls-audio-only 14.93 kB
/dom/media/vimeo 9.87 kB
/media/predicate 563 B
/i18n 2.66 kB 54.24 kB
/i18n/locales/all 30.58 kB
/i18n/locales/ar 1.21 kB
/i18n/locales/az 1.08 kB
/i18n/locales/bg 1.25 kB
/i18n/locales/bn 1.27 kB
/i18n/locales/bs 1014 B
/i18n/locales/ca 1.05 kB
/i18n/locales/cs 1.04 kB
/i18n/locales/cy 1.00 kB
/i18n/locales/da 996 B
/i18n/locales/de 1.08 kB
/i18n/locales/el 1.45 kB
/i18n/locales/en 621 B
/i18n/locales/es 1010 B
/i18n/locales/et 1.05 kB
/i18n/locales/eu 1.01 kB
/i18n/locales/fa 1.20 kB
/i18n/locales/fi 1.03 kB
/i18n/locales/fr 1.07 kB
/i18n/locales/gd 1.10 kB
/i18n/locales/gl 1014 B
/i18n/locales/he 1.12 kB
/i18n/locales/hi 1.28 kB
/i18n/locales/hr 1.02 kB
/i18n/locales/hu 1.09 kB
/i18n/locales/it 1023 B
/i18n/locales/ja 1.17 kB
/i18n/locales/ko 1.11 kB
/i18n/locales/lv 1.08 kB
/i18n/locales/mr 1.28 kB
/i18n/locales/nb 1000 B
/i18n/locales/ne 1.28 kB
/i18n/locales/nl 1013 B
/i18n/locales/nn 996 B
/i18n/locales/oc 1.05 kB
/i18n/locales/pl 1.12 kB
/i18n/locales/pt 1.01 kB
/i18n/locales/pt-BR 1.01 kB
/i18n/locales/pt-PT 1009 B
/i18n/locales/ro 1.05 kB
/i18n/locales/ru 1.33 kB
/i18n/locales/sk 1.10 kB
/i18n/locales/sl 1.02 kB
/i18n/locales/sr 1.03 kB
/i18n/locales/sv 1022 B
/i18n/locales/te 1.31 kB
/i18n/locales/th 1.29 kB
/i18n/locales/tr 1.07 kB
/i18n/locales/uk 1.36 kB
/i18n/locales/vi 1.08 kB
/i18n/locales/zh 1.01 kB
/i18n/locales/zh-CN 1.01 kB
/i18n/locales/zh-TW 1.01 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Initial
. 996 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Initial
. 1.39 kB
/html 696 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (11)
Entry Initial
/array 104 B
/dom 2.74 kB
/events 319 B
/function 327 B
/object 275 B
/predicate 265 B
/percent 281 B
/string 231 B
/style 190 B
/time 813 B
/number 158 B
📦 @videojs/spf — no changes
Entries (4)
Entry Initial
. 4.45 kB
/dom 6.32 kB
/hls 15.40 kB
/background-video 12.85 kB

ℹ️ How to interpret

JS sizes are initial static graph totals (minified + brotli). Lazy dynamic chunks are shown separately when present.

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

Run pnpm size locally to check current initial sizes.

@decepulis decepulis changed the title fix(site): restore react media element demos fix(site): restore react demos for ssr-safe media elements Jul 24, 2026
@decepulis
decepulis merged commit cc76fd0 into main Jul 24, 2026
26 checks passed
@decepulis
decepulis deleted the fix/restore-react-media-demos branch July 24, 2026 22:28
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.

2 participants