mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat: add DASH, Mux, and Vimeo as installation source types (UI + CLI) (#1732)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import * as p from '@clack/prompts';
|
||||
import { validateInstallationOptions } from '@/utils/installation/codegen';
|
||||
import { RENDERER_LABELS } from '@/utils/installation/renderer-options';
|
||||
import type { InstallMethod, Renderer, UseCase } from '@/utils/installation/types';
|
||||
import type { Framework } from '../utils/config.js';
|
||||
import { getConfigValue } from '../utils/config.js';
|
||||
@@ -58,7 +59,7 @@ function mapPresetToUseCase(preset: string): UseCase {
|
||||
return result;
|
||||
}
|
||||
|
||||
const ALL_RENDERERS: Renderer[] = ['html5-video', 'html5-audio', 'hls', 'background-video'];
|
||||
const ALL_RENDERERS = Object.keys(RENDERER_LABELS) as Renderer[];
|
||||
|
||||
function validateMedia(media: string): Renderer {
|
||||
if (!ALL_RENDERERS.includes(media as Renderer)) {
|
||||
@@ -114,7 +115,7 @@ Installation flags (for docs how-to/installation):
|
||||
--preset <video|audio|background-video>
|
||||
--skin <default|minimal|none>
|
||||
--source-url <url>
|
||||
--media <html5-video|html5-audio|hls|background-video>
|
||||
--media <html5-video|html5-audio|hls|dash|mux-video|mux-audio|vimeo|background-video>
|
||||
--install-method <cdn|npm|pnpm|yarn|bun>`;
|
||||
|
||||
export async function handleDocs(flags: ParsedFlags, positionals: string[]): Promise<void> {
|
||||
@@ -187,7 +188,9 @@ export async function handleDocs(flags: ParsedFlags, positionals: string[]): Pro
|
||||
// the non-interactive flag path so a `--install-method cdn` request for one
|
||||
// can't emit a broken snippet.
|
||||
if (opts.installMethod === 'cdn' && !supportsCdnInstall(opts.renderer)) {
|
||||
console.error('Error: this source type has no CDN build. Install it with npm, pnpm, yarn, or bun.');
|
||||
console.error(
|
||||
`Error: ${RENDERER_LABELS[opts.renderer]} has no CDN build. Install it with npm, pnpm, yarn, or bun.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -265,6 +265,41 @@ describe('handleDocs', () => {
|
||||
]);
|
||||
expect(output()).toContain('background-video-player');
|
||||
});
|
||||
|
||||
it('generates DASH media variant', async () => {
|
||||
await handleDocs(htmlFlags({ media: 'dash' }), ['how-to/installation']);
|
||||
const out = output();
|
||||
expect(out).toContain('<dash-video src=');
|
||||
expect(out).toContain("import '@videojs/html/media/dash-video'");
|
||||
});
|
||||
|
||||
it('generates Mux media variant', async () => {
|
||||
await handleDocs(htmlFlags({ media: 'mux-video' }), ['how-to/installation']);
|
||||
const out = output();
|
||||
expect(out).toContain('<mux-video src=');
|
||||
expect(out).toContain("import '@videojs/html/media/mux-video'");
|
||||
});
|
||||
|
||||
it('generates Vimeo media variant via npm', async () => {
|
||||
await handleDocs(htmlFlags({ media: 'vimeo' }), ['how-to/installation']);
|
||||
const out = output();
|
||||
expect(out).toContain('<vimeo-video src=');
|
||||
expect(out).toContain("import '@videojs/html/media/vimeo-video'");
|
||||
});
|
||||
|
||||
it('generates a CDN media script for renderers with a CDN build (mux)', async () => {
|
||||
await handleDocs(htmlFlags({ media: 'mux-video', 'install-method': 'cdn' }), ['how-to/installation']);
|
||||
const out = output();
|
||||
expect(out).toContain('<script');
|
||||
expect(out).toContain('media/mux-video.js');
|
||||
});
|
||||
|
||||
it('errors when requesting CDN for a renderer without a CDN build (vimeo)', async () => {
|
||||
await expect(
|
||||
handleDocs(htmlFlags({ media: 'vimeo', 'install-method': 'cdn' }), ['how-to/installation'])
|
||||
).rejects.toThrow(ExitError);
|
||||
expect(errors()).toContain('no CDN build');
|
||||
});
|
||||
});
|
||||
|
||||
describe('React framework', () => {
|
||||
|
||||
Vendored
+33
-3
@@ -7,7 +7,15 @@
|
||||
*/
|
||||
|
||||
declare module '@/utils/installation/types' {
|
||||
export type Renderer = 'background-video' | 'hls' | 'html5-audio' | 'html5-video';
|
||||
export type Renderer =
|
||||
| 'background-video'
|
||||
| 'dash'
|
||||
| 'hls'
|
||||
| 'html5-audio'
|
||||
| 'html5-video'
|
||||
| 'mux-audio'
|
||||
| 'mux-video'
|
||||
| 'vimeo';
|
||||
export type Skin = 'video' | 'audio' | 'minimal-video' | 'minimal-audio' | 'none';
|
||||
export type UseCase = 'default-video' | 'default-audio' | 'background-video';
|
||||
export type InstallMethod = 'cdn' | 'npm' | 'pnpm' | 'yarn' | 'bun';
|
||||
@@ -31,7 +39,8 @@ declare module '@/utils/installation/codegen' {
|
||||
export function validateInstallationOptions(opts: InstallationOptions): ValidationResult;
|
||||
|
||||
export function generateHTMLInstallCode(
|
||||
opts: Pick<InstallationOptions, 'useCase' | 'skin' | 'renderer'>
|
||||
opts: Pick<InstallationOptions, 'useCase' | 'skin' | 'renderer'>,
|
||||
cdnMediaSubpaths: readonly string[]
|
||||
): Record<'cdn' | 'npm' | 'pnpm' | 'yarn' | 'bun', string>;
|
||||
|
||||
export function generateReactInstallCode(): Record<'npm' | 'pnpm' | 'yarn' | 'bun', string>;
|
||||
@@ -63,10 +72,31 @@ declare module '@/utils/installation/detect-renderer' {
|
||||
declare module '@/utils/installation/cdn-code' {
|
||||
import type { Renderer, Skin, UseCase } from '@/utils/installation/types';
|
||||
|
||||
export function generateCdnCode(useCase: UseCase, skin: Skin, renderer: Renderer): string;
|
||||
export function generateCdnCode(
|
||||
useCase: UseCase,
|
||||
skin: Skin,
|
||||
renderer: Renderer,
|
||||
cdnMediaSubpaths: readonly string[]
|
||||
): string;
|
||||
export function rendererSupportsCdn(renderer: Renderer, cdnMediaSubpaths: readonly string[]): boolean;
|
||||
}
|
||||
|
||||
declare module '@/utils/installation/renderer-options' {
|
||||
import type { Renderer, UseCase } from '@/utils/installation/types';
|
||||
|
||||
// Mirrors the site's `SelectOption` shape, narrowed to the fields the CLI
|
||||
// uses. The site module imports that type from a React component; the CLI only
|
||||
// ever reads `value`/`label`.
|
||||
interface RendererOption {
|
||||
value: Renderer | null;
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const RENDERER_LABELS: Record<Renderer, string>;
|
||||
export function buildOptions(useCase: UseCase): RendererOption[];
|
||||
}
|
||||
|
||||
declare module '@/content/cdn-media.json' {
|
||||
const entries: Array<{ id: string }>;
|
||||
export default entries;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import cdnMedia from '@/content/cdn-media.json';
|
||||
import {
|
||||
generateHTMLInstallCode,
|
||||
generateHTMLUsageCode,
|
||||
@@ -7,6 +8,8 @@ import {
|
||||
type InstallationOptions,
|
||||
} from '@/utils/installation/codegen';
|
||||
|
||||
const CDN_MEDIA_SUBPATHS = cdnMedia.map((entry) => entry.id);
|
||||
|
||||
export function formatInstallationCode(opts: InstallationOptions): string {
|
||||
if (opts.framework === 'html') {
|
||||
return formatHTMLInstallation(opts);
|
||||
@@ -15,7 +18,7 @@ export function formatInstallationCode(opts: InstallationOptions): string {
|
||||
}
|
||||
|
||||
function formatHTMLInstallation(opts: InstallationOptions): string {
|
||||
const install = generateHTMLInstallCode(opts);
|
||||
const install = generateHTMLInstallCode(opts, CDN_MEDIA_SUBPATHS);
|
||||
const usage = generateHTMLUsageCode(opts);
|
||||
const sections: string[] = [];
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import cdnMedia from '@/content/cdn-media.json';
|
||||
import { rendererSupportsCdn } from '@/utils/installation/cdn-code';
|
||||
import type { InstallationOptions } from '@/utils/installation/codegen';
|
||||
import { detectRenderer } from '@/utils/installation/detect-renderer';
|
||||
import { buildOptions } from '@/utils/installation/renderer-options';
|
||||
import type { InstallMethod, Renderer, Skin, UseCase } from '@/utils/installation/types';
|
||||
import { VALID_RENDERERS } from '@/utils/installation/types';
|
||||
import type { Framework } from './config.js';
|
||||
|
||||
const CDN_MEDIA_SUBPATHS = cdnMedia.map((entry) => entry.id);
|
||||
@@ -32,17 +32,12 @@ const PRESET_OPTIONS: Array<{ value: UseCase; label: string }> = [
|
||||
{ value: 'background-video', label: 'Background Video' },
|
||||
];
|
||||
|
||||
// Reuse the installation page's option builder so labels and ordering stay in
|
||||
// lockstep with the UI.
|
||||
function mediaOptionsForUseCase(useCase: UseCase): Array<{ value: Renderer; label: string }> {
|
||||
const RENDERER_LABELS: Record<Renderer, string> = {
|
||||
'background-video': 'Background Video',
|
||||
hls: 'HLS',
|
||||
'html5-audio': 'HTML5 Audio',
|
||||
'html5-video': 'HTML5 Video',
|
||||
};
|
||||
|
||||
return VALID_RENDERERS[useCase].map((r) => ({
|
||||
value: r,
|
||||
label: RENDERER_LABELS[r],
|
||||
return buildOptions(useCase).map((option) => ({
|
||||
value: option.value as Renderer,
|
||||
label: option.label,
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { supportsCdnInstall } from '../prompts.js';
|
||||
|
||||
// Wires the cdn-media manifest into the CLI the same way the install page reads
|
||||
// the cdnMedia collection. Every current renderer ships (or is covered by) a
|
||||
// CDN build, so all resolve true; the no-CDN path (e.g. Vimeo) arrives with the
|
||||
// new rendering engines. `rendererSupportsCdn`'s false branch is unit-tested in
|
||||
// cdn-code.test.ts.
|
||||
// Mirrors the install page's CDN gating: preset renderers and media renderers
|
||||
// whose bundle ships a CDN build support CDN; Vimeo (no CDN build) does not.
|
||||
describe('supportsCdnInstall', () => {
|
||||
it('returns true for preset renderers (covered by the preset bundle)', () => {
|
||||
it('returns true for preset renderers', () => {
|
||||
expect(supportsCdnInstall('html5-video')).toBe(true);
|
||||
expect(supportsCdnInstall('html5-audio')).toBe(true);
|
||||
expect(supportsCdnInstall('background-video')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for hls, whose media bundle ships a CDN build', () => {
|
||||
it('returns true for media renderers with a CDN build', () => {
|
||||
expect(supportsCdnInstall('hls')).toBe(true);
|
||||
expect(supportsCdnInstall('dash')).toBe(true);
|
||||
expect(supportsCdnInstall('mux-video')).toBe(true);
|
||||
expect(supportsCdnInstall('mux-audio')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for vimeo, which has no CDN build', () => {
|
||||
expect(supportsCdnInstall('vimeo')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ const ALIASED_FILES = [
|
||||
'utils/installation/types.ts',
|
||||
'utils/installation/cdn-code.ts',
|
||||
'utils/installation/detect-renderer.ts',
|
||||
'utils/installation/renderer-options.ts',
|
||||
'consts.ts',
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user