Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: Add Solid integration #20991

Merged
merged 6 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion code/lib/cli/src/dirs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()],
Expand Down
8 changes: 8 additions & 0 deletions code/lib/cli/src/generators/SOLID/index.ts
Original file line number Diff line number Diff line change
@@ -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;
40 changes: 32 additions & 8 deletions code/lib/cli/src/generators/baseGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,33 @@ const getBuilderDetails = (builder: string) => {

const getExternalFramework = (framework: string) =>
externalFrameworks.find(
(exFramework) => exFramework.name === framework || exFramework.packageName === framework
(exFramework) =>
framework !== undefined &&
Copy link
Contributor

Choose a reason for hiding this comment

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

why would framework be undefined here, parameter typings suggests it can't be?

I'll admit though that I'm very confused about these typings, some places it's optional, other places it's not.

Copy link
Contributor Author

@webblocksapp webblocksapp Feb 9, 2023

Choose a reason for hiding this comment

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

The logic around external frameworks is getting a bit convoluted, but I think that's okay since all of this should only be temporary until we move external frameworks out of the CLI altogether.

I agree. It needs some refactoring in the future once you have standardized the new way for handling frameworks.

why would framework be undefined here, parameter typings suggests it can't be?

I think it's because the' undefined' type is considered in ts a subtype of all other types, including string.
For this reason, ts doesn't complain at line 92 when receives framework? from getFrameworkDetails fn. So It's needed to add this possible scenario when framework is 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) =>
Expand All @@ -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);
Expand All @@ -89,7 +107,7 @@ const getFrameworkDetails = (

if (isKnownFramework) {
return {
packages: [frameworkPackage],
packages: [rendererPackage, frameworkPackage],
framework: frameworkPackagePath,
rendererId: renderer,
type: 'framework',
Expand All @@ -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);
Expand Down Expand Up @@ -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`
Expand Down
6 changes: 6 additions & 0 deletions code/lib/cli/src/initiate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -206,6 +207,11 @@ const installStorybook = <Project extends ProjectType>(
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(
Expand Down
24 changes: 21 additions & 3 deletions code/lib/cli/src/project_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/<framework>
export type SupportedFrameworks = 'nextjs' | 'angular' | 'sveltekit' | 'qwik';
export type SupportedFrameworks = 'nextjs' | 'angular' | 'sveltekit' | 'qwik' | 'solid';

// Should match @storybook/<renderer>
export type SupportedRenderers =
Expand All @@ -42,7 +50,8 @@ export type SupportedRenderers =
| 'aurelia'
| 'html'
| 'web-components'
| 'server';
| 'server'
| 'solid';

export const SUPPORTED_RENDERERS: SupportedRenderers[] = [
'react',
Expand All @@ -60,6 +69,7 @@ export const SUPPORTED_RENDERERS: SupportedRenderers[] = [
'qwik',
'rax',
'aurelia',
'solid',
];

export enum ProjectType {
Expand Down Expand Up @@ -90,6 +100,7 @@ export enum ProjectType {
AURELIA = 'AURELIA',
SERVER = 'SERVER',
NX = 'NX',
SOLID = 'SOLID',
}

export enum CoreBuilder {
Expand Down Expand Up @@ -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
{
Expand Down
22 changes: 22 additions & 0 deletions code/lib/cli/src/sandbox-templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
1 change: 1 addition & 0 deletions code/lib/core-common/src/utils/get-storybook-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const rendererPackages: Record<string, string> = {
'storybook-framework-qwik': 'qwik',
'@storybook/rax': 'rax',
'@storybook/server': 'server',
'storybook-solidjs': 'solid',
};

const logger = console;
Expand Down