mirror of
https://github.com/zoriya/v10.git
synced 2026-08-05 05:37:21 +00:00
refactor(site): centralize demo media sources (#1829)
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import type { Plugin } from 'vite';
|
||||
import {
|
||||
VJS8_DEMO_VIDEO,
|
||||
VJS10_DEMO_BACKGROUND_VIDEO_MP4,
|
||||
VJS10_DEMO_DASH,
|
||||
VJS10_DEMO_POSTER,
|
||||
VJS10_DEMO_STORYBOARD,
|
||||
VJS10_DEMO_VIDEO,
|
||||
VJS10_MULTI_AUDIO_DEMO_VIDEO,
|
||||
} from '../src/consts.ts';
|
||||
|
||||
const DEMOS_DIRECTORY = '/src/components/docs/demos/';
|
||||
|
||||
export const DEMO_PLACEHOLDERS = {
|
||||
VJS8_DEMO_VIDEO_HLS: VJS8_DEMO_VIDEO.hls,
|
||||
VJS10_DEMO_BACKGROUND_VIDEO_MP4: VJS10_DEMO_BACKGROUND_VIDEO_MP4,
|
||||
VJS10_DEMO_DASH: VJS10_DEMO_DASH,
|
||||
VJS10_DEMO_POSTER: VJS10_DEMO_POSTER,
|
||||
VJS10_DEMO_STORYBOARD: VJS10_DEMO_STORYBOARD,
|
||||
VJS10_DEMO_VIDEO_HLS: VJS10_DEMO_VIDEO.hls,
|
||||
VJS10_DEMO_VIDEO_MP4: VJS10_DEMO_VIDEO.mp4,
|
||||
VJS10_MULTI_AUDIO_DEMO_VIDEO_HLS: VJS10_MULTI_AUDIO_DEMO_VIDEO.hls,
|
||||
} as const;
|
||||
|
||||
const PLACEHOLDER_PATTERN = /{{([A-Z0-9_]+)}}/g;
|
||||
|
||||
/** Resolve the shared media source placeholders used in demo snippets. */
|
||||
export function replaceDemoPlaceholders(source: string): string {
|
||||
return source.replace(PLACEHOLDER_PATTERN, (placeholder, name: string) => {
|
||||
const value = DEMO_PLACEHOLDERS[name as keyof typeof DEMO_PLACEHOLDERS];
|
||||
|
||||
if (!value) {
|
||||
throw new Error(`Unknown demo placeholder: ${placeholder}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
export function transformDemoPlaceholders(source: string, id: string): string | null {
|
||||
const [filePath, query = ''] = id.split('?', 2);
|
||||
const isRawHtml = filePath.endsWith('.html') && new URLSearchParams(query).has('raw');
|
||||
const isReactDemo = filePath.endsWith('.tsx');
|
||||
|
||||
if (!filePath.includes(DEMOS_DIRECTORY) || (!isRawHtml && !isReactDemo)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return replaceDemoPlaceholders(source);
|
||||
}
|
||||
|
||||
/** Resolve placeholders in HTML and React demos for the site build and dev server. */
|
||||
export function demoPlaceholderPlugin() {
|
||||
return {
|
||||
name: 'videojs:demo-placeholders',
|
||||
enforce: 'pre',
|
||||
transform: transformDemoPlaceholders,
|
||||
} satisfies Plugin;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { globSync, readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
DEMO_PLACEHOLDERS,
|
||||
demoPlaceholderPlugin,
|
||||
replaceDemoPlaceholders,
|
||||
transformDemoPlaceholders,
|
||||
} from '../replace-demo-placeholders.ts';
|
||||
|
||||
const DEMOS_DIRECTORY = resolve('src/components/docs/demos');
|
||||
|
||||
describe('replaceDemoPlaceholders', () => {
|
||||
it('resolves known placeholders', () => {
|
||||
const source = Object.keys(DEMO_PLACEHOLDERS)
|
||||
.map((name) => `{{${name}}}`)
|
||||
.join(' ');
|
||||
|
||||
expect(replaceDemoPlaceholders(source)).toBe(Object.values(DEMO_PLACEHOLDERS).join(' '));
|
||||
});
|
||||
|
||||
it('throws for unknown placeholders', () => {
|
||||
expect(() => replaceDemoPlaceholders('{{UNKNOWN_DEMO_VIDEO}}')).toThrow(
|
||||
'Unknown demo placeholder: {{UNKNOWN_DEMO_VIDEO}}'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('demoPlaceholderPlugin', () => {
|
||||
it('registers the demo transform as a pre-transform', () => {
|
||||
expect(demoPlaceholderPlugin()).toMatchObject({
|
||||
enforce: 'pre',
|
||||
transform: transformDemoPlaceholders,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformDemoPlaceholders', () => {
|
||||
it('resolves placeholders in raw HTML demo imports', () => {
|
||||
expect(
|
||||
transformDemoPlaceholders('{{VJS10_DEMO_VIDEO_MP4}}', '/site/src/components/docs/demos/play-button.html?raw')
|
||||
).toBe(DEMO_PLACEHOLDERS.VJS10_DEMO_VIDEO_MP4);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'/site/src/components/docs/demos/play-button/react/css/BasicUsage.tsx',
|
||||
'/site/src/components/docs/demos/play-button/react/css/BasicUsage.tsx?raw',
|
||||
])('resolves placeholders in React demo import %s', (id) => {
|
||||
expect(transformDemoPlaceholders('{{VJS10_DEMO_VIDEO_MP4}}', id)).toBe(DEMO_PLACEHOLDERS.VJS10_DEMO_VIDEO_MP4);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'/site/src/components/docs/demos/play-button.html?draw=true',
|
||||
'/site/src/components/docs/demos/play-button.ts?raw',
|
||||
'/site/src/components/play-button.html?raw',
|
||||
'/site/src/components/play-button.tsx',
|
||||
])('ignores unsupported demo import %s', (id) => {
|
||||
expect(transformDemoPlaceholders('{{VJS10_DEMO_VIDEO_MP4}}', id)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('demo placeholders', () => {
|
||||
it('does not hardcode shared demo media URLs', () => {
|
||||
const demoFiles = [
|
||||
...globSync('**/*.html', { cwd: DEMOS_DIRECTORY }),
|
||||
...globSync('**/*.tsx', { cwd: DEMOS_DIRECTORY }),
|
||||
];
|
||||
const hardcodedSources = demoFiles.filter((file) => {
|
||||
const source = readFileSync(resolve(DEMOS_DIRECTORY, file), 'utf8');
|
||||
return /https:\/\/(?:(?:stream|image)\.mux\.com|dash\.akamaized\.net|vimeo\.com)\//.test(source);
|
||||
});
|
||||
|
||||
expect(hardcodedSources).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user