diff --git a/code/lib/cli/src/dirs.ts b/code/lib/cli/src/dirs.ts index 1ac239604cf6..f7594b6a498a 100644 --- a/code/lib/cli/src/dirs.ts +++ b/code/lib/cli/src/dirs.ts @@ -8,7 +8,8 @@ export function getCliDir() { export function getRendererDir(renderer: SupportedFrameworks | SupportedRenderers) { const externalFramework = externalFrameworks.find((framework) => framework.name === renderer); - const frameworkPackageName = externalFramework?.packageName ?? `@storybook/${renderer}`; + const frameworkPackageName = + externalFramework?.renderer || externalFramework?.packageName || `@storybook/${renderer}`; return dirname( require.resolve(`${frameworkPackageName}/package.json`, { paths: [process.cwd()], diff --git a/code/lib/cli/src/generators/SOLID/index.ts b/code/lib/cli/src/generators/SOLID/index.ts new file mode 100644 index 000000000000..7dc517f667bb --- /dev/null +++ b/code/lib/cli/src/generators/SOLID/index.ts @@ -0,0 +1,8 @@ +import { baseGenerator } from '../baseGenerator'; +import type { Generator } from '../types'; + +const generator: Generator = async (packageManager, npmOptions, options) => { + await baseGenerator(packageManager, npmOptions, options, 'solid', {}, 'solid'); +}; + +export default generator; diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index d5cba7d07667..a31b8057826e 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -45,15 +45,33 @@ const getBuilderDetails = (builder: string) => { const getExternalFramework = (framework: string) => externalFrameworks.find( - (exFramework) => exFramework.name === framework || exFramework.packageName === framework + (exFramework) => + framework !== undefined && + (exFramework.name === framework || + exFramework.packageName === framework || + exFramework?.frameworks?.some?.((item) => item === framework)) ); const getFrameworkPackage = (framework: string, renderer: string, builder: string) => { const externalFramework = getExternalFramework(framework); - if (externalFramework) { - return externalFramework.packageName; + + if (externalFramework === undefined) { + return framework ? `@storybook/${framework}` : `@storybook/${renderer}-${builder}`; + } + + if (externalFramework.frameworks !== undefined) { + return externalFramework.frameworks.find((item) => item.match(new RegExp(`-${builder}`))); } - return framework ? `@storybook/${framework}` : `@storybook/${renderer}-${builder}`; + + return externalFramework.packageName; +}; + +const getRendererPackage = (framework: string, renderer: string) => { + const externalFramework = getExternalFramework(framework); + if (externalFramework !== undefined) + return externalFramework.renderer || externalFramework.packageName; + + return `@storybook/${renderer}`; }; const wrapForPnp = (packageName: string) => @@ -76,7 +94,7 @@ const getFrameworkDetails = ( const frameworkPackagePath = pnp ? wrapForPnp(frameworkPackage) : frameworkPackage; - const rendererPackage = `@storybook/${renderer}`; + const rendererPackage = getRendererPackage(framework, renderer); const rendererPackagePath = pnp ? wrapForPnp(rendererPackage) : rendererPackage; const builderPackage = getBuilderDetails(builder); @@ -89,7 +107,7 @@ const getFrameworkDetails = ( if (isKnownFramework) { return { - packages: [frameworkPackage], + packages: [rendererPackage, frameworkPackage], framework: frameworkPackagePath, rendererId: renderer, type: 'framework', @@ -114,7 +132,7 @@ const getFrameworkDetails = ( const stripVersions = (addons: string[]) => addons.map((addon) => getPackageDetails(addon)[0]); const hasInteractiveStories = (rendererId: SupportedRenderers) => - ['react', 'angular', 'preact', 'svelte', 'vue', 'vue3', 'html'].includes(rendererId); + ['react', 'angular', 'preact', 'svelte', 'vue', 'vue3', 'html', 'solid'].includes(rendererId); const hasFrameworkTemplates = (framework?: SupportedFrameworks) => ['angular', 'nextjs'].includes(framework); @@ -241,9 +259,15 @@ export async function baseGenerator( await configurePreview({ frameworkPreviewParts, storybookConfigFolder, language }); // FIXME: temporary workaround for https://github.com/storybookjs/storybook/issues/17516 + // Vite workaround regex for internal and external frameworks as f.e: + // Internal: @storybook/xxxxx-vite + // External: storybook-xxxxx-vite if ( frameworkPackages.find( - (pkg) => pkg.match(/^@storybook\/.*-vite$/) || pkg === '@storybook/sveltekit' + (pkg) => + pkg.match(/^(@storybook\/|storybook).*-vite$/) || + pkg === '@storybook/sveltekit' || + pkg === '' ) ) { const previewHead = dedent` diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index 1edf244404fe..a43948537a66 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -29,6 +29,7 @@ import svelteGenerator from './generators/SVELTE'; import qwikGenerator from './generators/QWIK'; import svelteKitGenerator from './generators/SVELTEKIT'; import raxGenerator from './generators/RAX'; +import solidGenerator from './generators/SOLID'; import serverGenerator from './generators/SERVER'; import type { JsPackageManager } from './js-package-manager'; import { JsPackageManagerFactory, useNpmWarning } from './js-package-manager'; @@ -206,6 +207,11 @@ const installStorybook = ( paddedLog('For more information, please see https://nx.dev/packages/storybook'); return Promise.reject(); + case ProjectType.SOLID: + return solidGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "SolidJS" app\n') + ); + case ProjectType.UNSUPPORTED: paddedLog(`We detected a project type that we don't support yet.`); paddedLog( diff --git a/code/lib/cli/src/project_types.ts b/code/lib/cli/src/project_types.ts index fcd3cb67b7c0..42fbbe4bd1bf 100644 --- a/code/lib/cli/src/project_types.ts +++ b/code/lib/cli/src/project_types.ts @@ -16,12 +16,20 @@ function eqMajor(versionRange: string, major: number) { } /** A list of all frameworks that are supported, but use a package outside the storybook monorepo */ -export const externalFrameworks: { name: SupportedFrameworks; packageName: string }[] = [ +export type ExternalFramework = { + name: SupportedFrameworks; + packageName?: string; + frameworks?: string[]; + renderer?: string; +}; + +export const externalFrameworks: ExternalFramework[] = [ { name: 'qwik', packageName: 'storybook-framework-qwik' }, + { name: 'solid', frameworks: ['storybook-solidjs-vite'], renderer: 'storybook-solidjs' }, ]; // Should match @storybook/ -export type SupportedFrameworks = 'nextjs' | 'angular' | 'sveltekit' | 'qwik'; +export type SupportedFrameworks = 'nextjs' | 'angular' | 'sveltekit' | 'qwik' | 'solid'; // Should match @storybook/ export type SupportedRenderers = @@ -42,7 +50,8 @@ export type SupportedRenderers = | 'aurelia' | 'html' | 'web-components' - | 'server'; + | 'server' + | 'solid'; export const SUPPORTED_RENDERERS: SupportedRenderers[] = [ 'react', @@ -60,6 +69,7 @@ export const SUPPORTED_RENDERERS: SupportedRenderers[] = [ 'qwik', 'rax', 'aurelia', + 'solid', ]; export enum ProjectType { @@ -90,6 +100,7 @@ export enum ProjectType { AURELIA = 'AURELIA', SERVER = 'SERVER', NX = 'NX', + SOLID = 'SOLID', } export enum CoreBuilder { @@ -285,6 +296,13 @@ export const supportedTemplates: TemplateConfiguration[] = [ return dependencies.every(Boolean); }, }, + { + preset: ProjectType.SOLID, + dependencies: ['solid-js'], + matcherFunction: ({ dependencies }) => { + return dependencies.every(Boolean); + }, + }, // DO NOT MOVE ANY TEMPLATES BELOW THIS LINE // React is part of every Template, after Storybook is initialized once { diff --git a/code/lib/cli/src/sandbox-templates.ts b/code/lib/cli/src/sandbox-templates.ts index c6b26f5e4c39..fe6a2ce5b8b2 100644 --- a/code/lib/cli/src/sandbox-templates.ts +++ b/code/lib/cli/src/sandbox-templates.ts @@ -145,6 +145,28 @@ const baseTemplates = { builder: '@storybook/builder-webpack5', }, }, + 'solid-vite/default-js': { + name: 'SolidJS Vite (JS)', + script: 'npx degit solidjs/templates/js .', + expected: { + framework: 'storybook-solidjs-vite', + renderer: 'storybook-solidjs', + builder: '@storybook/builder-vite', + }, + // TODO: remove this once solid-vite framework is released + inDevelopment: true, + }, + 'solid-vite/default-ts': { + name: 'SolidJS Vite (TS)', + script: 'npx degit solidjs/templates/ts .', + expected: { + framework: 'storybook-solidjs-vite', + renderer: 'storybook-solidjs', + builder: '@storybook/builder-vite', + }, + // TODO: remove this once solid-vite framework is released + inDevelopment: true, + }, 'vue3-vite/default-js': { name: 'Vue3 Vite (JS)', script: 'yarn create vite . --template vue', diff --git a/code/lib/core-common/src/utils/get-storybook-info.ts b/code/lib/core-common/src/utils/get-storybook-info.ts index 556d57049f00..d1d77fac6368 100644 --- a/code/lib/core-common/src/utils/get-storybook-info.ts +++ b/code/lib/core-common/src/utils/get-storybook-info.ts @@ -20,6 +20,7 @@ const rendererPackages: Record = { 'storybook-framework-qwik': 'qwik', '@storybook/rax': 'rax', '@storybook/server': 'server', + 'storybook-solidjs': 'solid', }; const logger = console;