From 8eb2662c16750d6adb5f19982794a8d558b0a297 Mon Sep 17 00:00:00 2001 From: Rahim Date: Sat, 29 Aug 2026 08:21:15 -0700 Subject: [PATCH] build(skin): generate hosted shadcn catalogs --- packages/skins/package.json | 2 + packages/skins/shadcn/format.ts | 39 ++++++++ packages/skins/shadcn/vite.config.ts | 4 +- packages/skins/vite.config.ts | 30 +++++- pnpm-lock.yaml | 137 ++++++++++++++++----------- 5 files changed, 155 insertions(+), 57 deletions(-) create mode 100644 packages/skins/shadcn/format.ts diff --git a/packages/skins/package.json b/packages/skins/package.json index 1f4ab089eb..0b5bada758 100644 --- a/packages/skins/package.json +++ b/packages/skins/package.json @@ -55,8 +55,10 @@ "dashjs": "^5.2.0", "hls.js": "^1.6.7", "mux-embed": "5.17.10", + "oxfmt": "0.61.0", "react": "^19.2.8", "react-dom": "^19.2.8", + "shadcn": "^4.19.0", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.3.3", "typescript": "^6.0.2", diff --git a/packages/skins/shadcn/format.ts b/packages/skins/shadcn/format.ts new file mode 100644 index 0000000000..18aacf5c67 --- /dev/null +++ b/packages/skins/shadcn/format.ts @@ -0,0 +1,39 @@ +import { isString } from '@videojs/utils/predicate'; +import { format } from 'oxfmt'; +import type { Plugin } from 'vite'; + +const sourceFile = /\.(?:css|[cm]?[jt]sx?)$/; + +/** Format editable registry source before Shadcn embeds it in installable item JSON. */ +export function formatRegistrySources(): Plugin { + return { + name: 'videojs:format-registry-sources', + async generateBundle(_options, bundle) { + await Promise.all( + Object.values(bundle).map(async (asset) => { + if (asset.type !== 'asset' || !isString(asset.source) || !sourceFile.test(asset.fileName)) return; + + const result = await format(asset.fileName, asset.source, { + arrowParens: 'always', + bracketSpacing: true, + jsdoc: true, + printWidth: 120, + semi: true, + singleQuote: !asset.fileName.endsWith('.css'), + sortImports: true, + tabWidth: 2, + trailingComma: 'es5', + }); + + if (result.errors.length > 0) { + const messages = result.errors.map((error) => error.message).join('\n'); + + throw new Error(`Could not format generated registry source \`${asset.fileName}\`:\n${messages}`); + } + + asset.source = result.code; + }) + ); + }, + }; +} diff --git a/packages/skins/shadcn/vite.config.ts b/packages/skins/shadcn/vite.config.ts index 5a41f770c0..b569effb9a 100644 --- a/packages/skins/shadcn/vite.config.ts +++ b/packages/skins/shadcn/vite.config.ts @@ -18,6 +18,7 @@ import type { VjscRegistryItem } from '../../vjsc/src/shadcn/index.ts'; import type { VideojsRegistryMeta } from '../registry/meta.ts'; import { configureSkinModule } from '../vjsc/config'; import { type SkinModuleMeta, type SkinName, skinStyles } from '../vjsc/meta'; +import { formatRegistrySources } from './format'; const packageDir = resolve(import.meta.dirname, '..'); const vjscDir = resolve(packageDir, 'vjsc'); @@ -112,7 +113,7 @@ export const shadcnPackConfig: PackUserConfig = { name: 'skins-shadcn-registry', cwd: packageDir, entry: { registry: registryUtils }, - outDir: 'dist/registry', + outDir: 'dist/registry/source', clean: true, dts: false, sourcemap: false, @@ -144,6 +145,7 @@ export const shadcnPackConfig: PackUserConfig = { items: registryItems(target), }) ), + formatRegistrySources(), registryAssetsOnly(), ], }; diff --git a/packages/skins/vite.config.ts b/packages/skins/vite.config.ts index 1f112fdc51..2a0d7d183d 100644 --- a/packages/skins/vite.config.ts +++ b/packages/skins/vite.config.ts @@ -34,13 +34,37 @@ export default defineConfig({ input: cachedTaskInputs, output: ['dist/**', '!dist/registry', '!dist/registry/**'], }, - 'build:shadcn': { - command: 'vp -C shadcn pack', + 'prepare:shadcn': { + command: ['rimraf dist/registry', 'vp -C shadcn pack'], dependsOn: workspaceTaskDependencies(), // The registry plugin compares files in its output directory before // rewriting them; those reads must not turn outputs into inputs. input: [...cachedTaskInputs, '!dist/registry', '!dist/registry/**'], - output: ['dist/registry/**'], + output: ['dist/registry/source/**'], + }, + 'build:shadcn:react': { + command: 'shadcn build dist/registry/source/r/react/registry.json --output dist/registry/r/react', + dependsOn: ['prepare:shadcn'], + input: ['dist/registry/source/r/react/**', '!dist/registry/source/r/react/css/**'], + output: ['dist/registry/r/react/**', '!dist/registry/r/react/css/**'], + }, + 'build:shadcn:react-css': { + command: 'shadcn build dist/registry/source/r/react/css/registry.json --output dist/registry/r/react/css', + dependsOn: ['build:shadcn:react'], + input: ['dist/registry/source/r/react/css/**'], + output: ['dist/registry/r/react/css/**'], + }, + 'build:shadcn:html': { + command: 'shadcn build dist/registry/source/r/html/registry.json --output dist/registry/r/html', + dependsOn: ['prepare:shadcn'], + input: ['dist/registry/source/r/html/**', '!dist/registry/source/r/html/css/**'], + output: ['dist/registry/r/html/**', '!dist/registry/r/html/css/**'], + }, + 'build:shadcn': { + command: 'shadcn build dist/registry/source/r/html/css/registry.json --output dist/registry/r/html/css', + dependsOn: ['build:shadcn:html', 'build:shadcn:react-css'], + input: ['dist/registry/source/r/html/css/**'], + output: ['dist/registry/r/html/css/**'], }, 'test:ci': packageTestTask('pnpm run test:types && vp test run'), }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad9049ae80..6167fe8626 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -510,12 +510,18 @@ importers: mux-embed: specifier: 5.17.10 version: 5.17.10 + oxfmt: + specifier: 0.61.0 + version: 0.61.0(vite-plus@0.2.8(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(@vitest/ui@4.1.10)(@voidzero-dev/vite-plus-core@0.2.8(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.50.0)(tsx@4.23.1)(typescript@6.0.2)(unrun@0.2.39)(yaml@2.9.0))(esbuild@0.28.1)(happy-dom@20.11.1)(jiti@2.7.0)(jsdom@27.4.0(supports-color@8.1.1))(terser@5.50.0)(tsx@4.23.1)(typescript@6.0.2)(unrun@0.2.39)(yaml@2.9.0)) react: specifier: ^19.2.8 version: 19.2.8 react-dom: specifier: ^19.2.8 version: 19.2.8(react@19.2.8) + shadcn: + specifier: ^4.19.0 + version: 4.19.0(supports-color@8.1.1)(typescript@6.0.2) tailwind-merge: specifier: ^3.5.0 version: 3.5.0 @@ -1120,10 +1126,6 @@ packages: peerDependencies: playwright-core: '>= 1.0.0' - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} @@ -1286,10 +1288,6 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} - engines: {node: '>=6.9.0'} - '@babel/types@7.29.8': resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} @@ -7893,11 +7891,6 @@ packages: mux-embed@5.18.1: resolution: {integrity: sha512-ePsHjiEKY+FgrSBiMmaF+LOtTQSSBWv/1zqpREQFN96JE93xlsArT/MEi30yKOE06MgjOlL70YI750molu3y7g==} - nanoid@3.3.16: - resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - nanoid@3.3.18: resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -8401,10 +8394,6 @@ packages: peerDependencies: postcss: ^8.2.9 - postcss@8.5.22: - resolution: {integrity: sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.26: resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} engines: {node: ^10 || ^12 || >=14} @@ -8846,6 +8835,11 @@ packages: engines: {node: '>=20.18.1'} hasBin: true + shadcn@4.19.0: + resolution: {integrity: sha512-EQF6R+CUXTsEP2BpyhxrUEAFesrtFD1POvVOf5jM+wkgtA4kG1EW1+1Wlmi9LqiprSL681JJXBcS0u8WkVVVyQ==} + engines: {node: '>=20.18.1'} + hasBin: true + shaka-player@5.2.6: resolution: {integrity: sha512-/AIgm9CzhTJu5Ba5l6kKczQn7k6MeMqpQmbtvRrUfgYnWxnQfZ20bhQd7TtD5sCypE9x+nr9vxA6bVBlz+nP8A==} engines: {node: '>=18'} @@ -8922,6 +8916,10 @@ packages: slashes@3.0.12: resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smol-toml@1.6.0: resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} engines: {node: '>= 18'} @@ -8933,6 +8931,10 @@ packages: snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + socks@2.8.9: + resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -10493,12 +10495,6 @@ snapshots: axe-core: 4.13.0 playwright-core: 1.59.1 - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.29.7 - js-tokens: 4.0.0 - picocolors: 1.1.1 - '@babel/code-frame@7.29.7': dependencies: '@babel/helper-validator-identifier': 7.29.7 @@ -10537,7 +10533,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-compilation-targets@7.28.6': dependencies: @@ -10565,7 +10561,7 @@ snapshots: '@babel/helper-member-expression-to-functions@7.29.7(supports-color@8.1.1)': dependencies: '@babel/traverse': 7.29.8(supports-color@8.1.1) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -10587,7 +10583,7 @@ snapshots: '@babel/helper-optimise-call-expression@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-plugin-utils@7.28.6': {} @@ -10605,7 +10601,7 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@8.1.1)': dependencies: '@babel/traverse': 7.29.8(supports-color@8.1.1) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -10624,7 +10620,7 @@ snapshots: '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/parser@7.29.8': dependencies: @@ -10707,11 +10703,6 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.29.7 - '@babel/types@7.29.7': - dependencies: - '@babel/helper-string-parser': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - '@babel/types@7.29.8': dependencies: '@babel/helper-string-parser': 7.29.7 @@ -11943,8 +11934,8 @@ snapshots: '@netlify/zip-it-and-ship-it@14.7.1(rollup@4.59.0)(supports-color@8.1.1)': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@netlify/binary-info': 1.0.0 '@netlify/serverless-functions-api': 2.16.0 '@vercel/nft': 0.29.4(rollup@4.59.0)(supports-color@8.1.1) @@ -13355,16 +13346,16 @@ snapshots: '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 '@types/chai@5.2.3': dependencies: @@ -14153,7 +14144,7 @@ snapshots: '@vue/compiler-core@3.5.40': dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/shared': 3.5.40 entities: 7.0.1 estree-walker: 2.0.2 @@ -14166,7 +14157,7 @@ snapshots: '@vue/compiler-sfc@3.5.40': dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/compiler-core': 3.5.40 '@vue/compiler-dom': 3.5.40 '@vue/compiler-ssr': 3.5.40 @@ -17657,8 +17648,6 @@ snapshots: mux-embed@5.18.1: {} - nanoid@3.3.16: {} - nanoid@3.3.18: {} nanostores@1.1.1: {} @@ -17716,7 +17705,7 @@ snapshots: node-source-walk@7.0.2: dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 node-stream-zip@1.16.0: {} @@ -18329,7 +18318,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -18445,12 +18434,6 @@ snapshots: postcss: 8.5.26 quote-unquote: 1.0.0 - postcss@8.5.22: - dependencies: - nanoid: 3.3.16 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.26: dependencies: nanoid: 3.3.18 @@ -19087,7 +19070,7 @@ snapshots: shadcn@4.16.2(supports-color@8.1.1)(typescript@6.0.2): dependencies: '@babel/core': 7.29.0(supports-color@8.1.1) - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1) '@babel/preset-typescript': 7.29.7(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1) '@dotenvx/dotenvx': 1.75.1 @@ -19106,7 +19089,7 @@ snapshots: kleur: 4.1.5 open: 11.0.0 ora: 8.2.0 - postcss: 8.5.22 + postcss: 8.5.26 postcss-selector-parser: 7.1.5 prompts: 2.4.2 recast: 0.23.19 @@ -19124,6 +19107,47 @@ snapshots: - supports-color - typescript + shadcn@4.19.0(supports-color@8.1.1)(typescript@6.0.2): + dependencies: + '@babel/core': 7.29.0(supports-color@8.1.1) + '@babel/parser': 7.29.8 + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1) + '@dotenvx/dotenvx': 1.75.1 + '@modelcontextprotocol/sdk': 1.30.0(supports-color@8.1.1)(zod@3.25.76) + '@types/validate-npm-package-name': 4.0.2 + browserslist: 4.28.1 + commander: 14.0.3 + cosmiconfig: 9.0.1(typescript@6.0.2) + dedent: 1.7.2 + deepmerge: 4.3.1 + diff: 8.0.4 + execa: 9.6.1 + fast-glob: 3.3.3 + fs-extra: 11.4.0 + fuzzysort: 3.1.0 + kleur: 4.1.5 + open: 11.0.0 + ora: 8.2.0 + postcss: 8.5.26 + postcss-selector-parser: 7.1.5 + prompts: 2.4.2 + recast: 0.23.19 + socks: 2.8.9 + stringify-object: 5.0.0 + tailwind-merge: 3.5.0 + ts-morph: 26.0.0 + tsconfig-paths: 4.2.0 + undici: 7.29.0 + validate-npm-package-name: 7.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - '@cfworker/json-schema' + - babel-plugin-macros + - supports-color + - typescript + shaka-player@5.2.6: {} sharp@0.34.5: @@ -19270,6 +19294,8 @@ snapshots: slashes@3.0.12: {} + smart-buffer@4.2.0: {} + smol-toml@1.6.0: {} smol-toml@1.7.0: {} @@ -19279,6 +19305,11 @@ snapshots: dot-case: 3.0.4 tslib: 2.8.1 + socks@2.8.9: + dependencies: + ip-address: 10.4.0 + smart-buffer: 4.2.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: