Skip to content

feat: add a CDN media-availability manifest and read it across install surfaces#1737

Open
decepulis wants to merge 5 commits into
mainfrom
claude/cdn-media-manifest
Open

feat: add a CDN media-availability manifest and read it across install surfaces#1737
decepulis wants to merge 5 commits into
mainfrom
claude/cdn-media-manifest

Conversation

@decepulis

@decepulis decepulis commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

So I'm working towards #1255 -- putting media elements on the installation page -- and it's come up that not all media elements have a cdn distro. So the installation page needs to know which ones do and don't.

This PR addresses that gap.

  1. It reads the source code and generates a manifest of CDN-ified media elements.
  2. It reads that manifest in the installation doc (for humans) and the CLI (for the robots)

This PR is a prerequisite to #1732.

How do I review this?

There's kinda three slices of code to know about

Manifest generation

  1. scripts/build-cdn-manifest.ts is an ai-driven black box that does the reading.
  2. turbo.json makes sure it's called at the right time.
  3. content.config.ts tells astro what to expect from the manifest.
  4. rendererSupportsCdn() reads the manifest and does the checking.

UI for humans

  • HTMLInstallTabs.astro / HTMLInstallTabsClient.tsx calls rendererSupportsCdn() and does some UI stuff in response

CLI for Robots

  • @videojs/cli reads the same manifest (bundled by tsdown; a committed fixture backs the hermetic tests), exposes supportsCdnInstall, offers the CDN install method only when the renderer ships a CDN build, and rejects --install-method cdn for one that doesn't.

https://claude.ai/code/session_01Kd5A9UsSz5Ka7nYhEik3Fd


Note

Low Risk
Changes are limited to install UX, generated docs content, and build tooling; no runtime player or auth paths are modified.

Overview
Adds a build-time CDN media manifest derived from @videojs/html CDN output so install flows know which renderers actually ship CDN bundles.

A new cdn-manifest script writes gitignored cdn-media.json, wired into site dev/build via Turbo (after build:cdn) and exposed as the cdnMedia Astro collection. Shared logic rendererSupportsCdn treats preset renderers as always CDN-capable and requires a media renderer’s subpath (e.g. hls-video) to appear in that manifest.

On the installation doc, HTML install tabs now load the manifest server-side and hide the CDN tab (with a short npm-only message) when the selected renderer has no CDN build, including a keyed remount so tab state stays in sync.

The CLI bundles the same manifest, offers CDN only in prompts when supported, and errors on --install-method cdn for unsupported renderers so generated snippets can’t reference missing CDN scripts. Hermetic CLI tests use a committed fixture mirroring the manifest shape.

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

Generate a build-time manifest of which @videojs/html media subpaths ship
a CDN build, and wire the installation guide's HTML install tabs to hide
the CDN option (falling back to a package manager) for any renderer that
lacks a CDN bundle.

- build-cdn-manifest.ts scans packages/html/cdn/media and writes
  src/content/cdn-media.json, exposed via a cdnMedia content collection
- turbo cdn-manifest task (dependsOn ^build:cdn) runs before build/dev
- HTMLInstallSection.astro reads the manifest server-side and passes it to
  the HTMLInstallTabs island, which reacts to the selected renderer
- rendererSupportsCdn() centralizes the availability check

Behavior is unchanged for current renderers (all have CDN builds); this is
the machinery that lets renderers without a CDN build (e.g. Vimeo) drop the
CDN install option.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kd5A9UsSz5Ka7nYhEik3Fd
@netlify

netlify Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit ea47cb6
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6a3c77755bc99e0008361f90
😎 Deploy Preview https://deploy-preview-1737--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 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 Jun 25, 2026 12:34am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Initial
/video (default) 44.32 kB
/video (default + hls) 183.79 kB
/video (minimal) 43.98 kB
/video (minimal + hls) 183.63 kB
/audio (default) 37.83 kB
/audio (minimal) 36.61 kB
/background 4.20 kB
Media (10)
Entry Initial
/media/background-video 1.14 kB
/media/container 1.72 kB
/media/dash-video 214.74 kB
/media/hls-video 141.27 kB
/media/mux-audio 163.91 kB
/media/mux-video 163.68 kB
/media/native-hls-video 9.05 kB
/media/simple-hls-audio-only 17.15 kB
/media/simple-hls-video 18.69 kB
/media/vimeo-video 12.31 kB
Players (5)
Entry Initial
/video/player 8.07 kB
/audio/player 5.38 kB
/background/player 3.92 kB
/live-video/player 7.64 kB
/live-audio/player 5.39 kB
Skins (30)
Entry Type Initial
/video/minimal-skin.css css 5.45 kB
/video/skin.css css 5.43 kB
/video/minimal-skin js 44.01 kB
/video/minimal-skin.tailwind js 44.58 kB
/video/skin js 44.28 kB
/video/skin.tailwind js 44.98 kB
/audio/minimal-skin.css css 3.60 kB
/audio/skin.css css 3.53 kB
/audio/minimal-skin js 36.62 kB
/audio/minimal-skin.tailwind js 37.04 kB
/audio/skin js 37.80 kB
/audio/skin.tailwind js 38.25 kB
/background/skin.css css 133 B
/background/skin js 1.14 kB
/live-video/minimal-skin.css css 5.45 kB
/live-video/skin.css css 5.43 kB
/live-video/minimal-skin js 43.12 kB
/live-video/minimal-skin.tailwind js 43.58 kB
/live-video/skin js 43.08 kB
/live-video/skin.tailwind js 43.58 kB
/live-audio/minimal-skin.css css 3.60 kB
/live-audio/skin.css css 3.53 kB
/live-audio/minimal-skin js 29.73 kB
/live-audio/minimal-skin.tailwind js 29.20 kB
/live-audio/skin js 31.04 kB
/live-audio/skin.tailwind js 30.66 kB
/global.css css 176 B
/shared.css css 88 B
/tailwind.css css 228 B
/skin-element js 1.44 kB
UI Components (38)
Entry Initial
/ui/airplay-button 2.29 kB
/ui/alert-dialog 2.45 kB
/ui/alert-dialog-close 2.15 kB
/ui/alert-dialog-description 2.18 kB
/ui/alert-dialog-title 2.17 kB
/ui/buffering-indicator 2.24 kB
/ui/captions-button 2.37 kB
/ui/captions-radio-group 2.73 kB
/ui/cast-button 2.25 kB
/ui/compounds 2.85 kB
/ui/controls 2.58 kB
/ui/error-dialog 2.61 kB
/ui/fullscreen-button 2.29 kB
/ui/hotkey 2.31 kB
/ui/menu 2.63 kB
/ui/mute-button 2.27 kB
/ui/pip-button 2.28 kB
/ui/play-button 2.28 kB
/ui/playback-rate-button 2.36 kB
/ui/playback-rate-radio-group 2.78 kB
/ui/popover 2.64 kB
/ui/poster 2.14 kB
/ui/quality-radio-group 2.75 kB
/ui/seek-button 2.27 kB
/ui/seek-indicator 2.29 kB
/ui/seek-indicator-value 465 B
/ui/slider 2.62 kB
/ui/status-announcer 2.28 kB
/ui/status-indicator 2.36 kB
/ui/status-indicator-value 467 B
/ui/thumbnail 2.09 kB
/ui/time 2.60 kB
/ui/time-slider 2.64 kB
/ui/tooltip 2.59 kB
/ui/volume-indicator 2.36 kB
/ui/volume-indicator-fill 410 B
/ui/volume-indicator-value 426 B
/ui/volume-slider 2.64 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react — no changes
Presets (7)
Entry Initial
/video (default) 36.83 kB
/video (default + hls) 175.18 kB
/video (minimal) 36.91 kB
/video (minimal + hls) 175.13 kB
/audio (default) 29.97 kB
/audio (minimal) 30.04 kB
/background 754 B
Media (9)
Entry Initial
/media/background-video 575 B
/media/dash-video 213.24 kB
/media/hls-video 139.80 kB
/media/mux-audio 162.26 kB
/media/mux-video 162.26 kB
/media/native-hls-video 7.39 kB
/media/simple-hls-audio-only 15.56 kB
/media/simple-hls-video 17.15 kB
/media/vimeo-video 10.58 kB
Skins (27)
Entry Type Initial
/tailwind.css css 228 B
/video/minimal-skin.css css 5.37 kB
/video/skin.css css 5.34 kB
/video/minimal-skin js 36.81 kB
/video/minimal-skin.tailwind js 42.58 kB
/video/skin js 36.73 kB
/video/skin.tailwind js 42.51 kB
/audio/minimal-skin.css css 3.47 kB
/audio/skin.css css 3.39 kB
/audio/minimal-skin js 29.98 kB
/audio/minimal-skin.tailwind js 31.76 kB
/audio/skin js 29.91 kB
/audio/skin.tailwind js 33.75 kB
/background/skin.css css 90 B
/background/skin js 272 B
/live-video/minimal-skin.css css 5.37 kB
/live-video/skin.css css 5.34 kB
/live-video/minimal-skin js 32.56 kB
/live-video/minimal-skin.tailwind js 38.22 kB
/live-video/skin js 32.58 kB
/live-video/skin.tailwind js 38.24 kB
/live-audio/minimal-skin.css css 3.47 kB
/live-audio/skin.css css 3.39 kB
/live-audio/minimal-skin js 21.74 kB
/live-audio/minimal-skin.tailwind js 24.64 kB
/live-audio/skin js 21.78 kB
/live-audio/skin.tailwind js 24.78 kB
UI Components (32)
Entry Initial
/ui/airplay-button 2.23 kB
/ui/alert-dialog 2.20 kB
/ui/buffering-indicator 2.10 kB
/ui/captions-button 2.16 kB
/ui/captions-radio-group 2.09 kB
/ui/cast-button 2.19 kB
/ui/controls 2.05 kB
/ui/error-dialog 2.24 kB
/ui/fullscreen-button 2.26 kB
/ui/gesture 2.25 kB
/ui/hotkey 2.27 kB
/ui/live-button 2.12 kB
/ui/menu 2.43 kB
/ui/mute-button 2.24 kB
/ui/pip-button 2.26 kB
/ui/play-button 2.19 kB
/ui/playback-rate 2.06 kB
/ui/playback-rate-button 2.25 kB
/ui/popover 2.64 kB
/ui/poster 2.09 kB
/ui/quality 2.10 kB
/ui/seek-button 2.20 kB
/ui/seek-indicator 2.19 kB
/ui/slider 2.26 kB
/ui/status-announcer 2.11 kB
/ui/status-indicator 2.15 kB
/ui/thumbnail 2.00 kB
/ui/time 2.05 kB
/ui/time-slider 2.29 kB
/ui/tooltip 2.59 kB
/ui/volume-indicator 2.18 kB
/ui/volume-slider 2.30 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core — no changes
Entries (14)
Entry Initial
. 9.08 kB
/dom 17.02 kB
/dom/media/custom-media-element 2.09 kB
/dom/media/dash 209.07 kB
/dom/media/google-cast 4.04 kB
/dom/media/hls 135.63 kB
/dom/media/media-host 1.25 kB
/dom/media/media-played-ranges 576 B
/dom/media/mux 151.26 kB
/dom/media/native-hls 3.05 kB
/dom/media/simple-hls 16.47 kB
/dom/media/simple-hls-audio-only 14.92 kB
/dom/media/vimeo 9.86 kB
/media/predicate 573 B
🏷️ @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 (10)
Entry Initial
/array 104 B
/dom 2.26 kB
/events 319 B
/function 327 B
/object 275 B
/predicate 265 B
/string 231 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (4)
Entry Initial
. 4.45 kB
/dom 6.33 kB
/hls 15.37 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 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude, for when you're done with your current task, here's a few cleanup items

Comment thread site/src/components/installation/HTMLInstallSection.astro Outdated
Comment thread site/src/components/installation/HTMLInstallTabs.tsx Outdated
Comment thread site/src/components/installation/HTMLInstallTabs.tsx Outdated
- Rename the install component's halves to the server/client convention
  used elsewhere (JSPicker, SkinPickerSection): HTMLInstallSection.astro →
  HTMLInstallTabs.astro and HTMLInstallTabs.tsx → HTMLInstallTabsClient.tsx.
- DRY the paragraph styling: extract `p`/`pMaxWidth` into typography/styles.ts
  and consume from both P.astro and the CDN-unavailable note in the React
  island (which can't use the Astro <P> component).
- Simplify the tab→installMethod sync: one MutationObserver on the tabs root
  with `subtree: true` catches data-tab-active flips on any tab, including the
  CDN tab when it's added/removed, so it no longer re-attaches on a derived
  dependency. The effect deps are now empty and honest — no lint suppression.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kd5A9UsSz5Ka7nYhEik3Fd
The installation page reads the cdn-media manifest to hide the CDN option
for renderers without a CDN build. Wire the same gating into the CLI so the
two surfaces stay in lockstep:

- Read the generated manifest (bundled by tsdown; a committed fixture backs
  the hermetic tests) and expose `supportsCdnInstall`.
- Offer the CDN install method only when the renderer ships a CDN build, and
  reject `--install-method cdn` for one that doesn't in the non-interactive
  flag path.
- Extend the bundled-site type shim with the cdn-code module and the
  cdn-media.json import; alias the manifest in tsdown and vitest.

Behavior-neutral on the current renderers (all ship a CDN build); the gating
takes visible effect alongside the new rendering engines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kd5A9UsSz5Ka7nYhEik3Fd
@decepulis decepulis changed the title feat(site): add CDN media availability manifest for installation guide feat: add a CDN media-availability manifest and read it across install surfaces Jun 24, 2026
@decepulis decepulis marked this pull request as ready for review June 24, 2026 21:23

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a4b2627. Configure here.

Comment thread site/src/components/installation/HTMLInstallTabsClient.tsx
Comment thread packages/cli/src/utils/prompts.ts Outdated
Comment thread packages/cli/src/utils/prompts.ts Outdated

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bummer that this is marked as a deletion, not a rename, in git.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah — that's GitHub's rename detection, which is similarity-based on the aggregate base↔head content of the file, not on commit structure. The rename landed in the same change as the observer rewrite + styling refactor (and now the desync fix touches it again), so the new HTMLInstallTabsClient.tsx is similar enough to less than GitHub's threshold against the old HTMLInstallTabs.tsx, and it falls back to delete + add.

I can't force it back to a "renamed" badge without shrinking that net diff (which would mean undoing the refactors). Splitting the rename into its own pure git mv commit wouldn't help the squashed/Files-changed view either, since that compares final content regardless of commit boundaries — though it would read as a clean rename if you review commit-by-commit. Happy to restructure the commits that way if that's how you review; otherwise it's purely cosmetic and the file's history is intact via git log --follow.


Generated by Claude Code

When the selected renderer toggled CDN support, the npm tab's reactive
`initial` flip and the CDN tab mounting/unmounting set `data-tab-active`
without clearing the previously-active tab — leaving two tabs active, so
the observer's "first active tab" could disagree with the visible tab and
the usage snippet. (Bugbot, medium severity.)

Remount the tab set via `key` on CDN-availability change so the active tab
resets cleanly to its initial, and observe `data-tab-active` from the stable
wrapper so the observer survives the remount. This makes the separate
cdn→npm reconcile effect redundant.

Also drop two comments in the CLI's prompts.ts that restated the code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kd5A9UsSz5Ka7nYhEik3Fd
Comment thread site/src/components/typography/styles.ts Outdated
Per review: the centered max reading width is used for prose, so `prose`
reads better than `pMaxWidth`. Renamed across styles.ts, P.astro, and the
install-tabs note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kd5A9UsSz5Ka7nYhEik3Fd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants