From 5ae7917ea31c6729d94da0e487ebec6fb07b5bbb Mon Sep 17 00:00:00 2001 From: Benjamin Kindle Date: Fri, 13 Jan 2023 17:20:25 -0500 Subject: [PATCH] feat: support Qwik framework in sb init Works with this change in the storybook-framework-qwik project: https://github.com/literalpie/storybook-framework-qwik/commit/3dca5b48de2af92c8c767fd95d78963ae1898fc0 --- README.md | 1 + code/lib/cli/src/detect.test.ts | 10 +++++++++ code/lib/cli/src/dirs.ts | 7 ++++++- code/lib/cli/src/generators/QWIK/index.ts | 8 +++++++ code/lib/cli/src/generators/baseGenerator.ts | 21 ++++++++++++++----- code/lib/cli/src/initiate.ts | 7 +++++++ code/lib/cli/src/project_types.ts | 16 +++++++++++++- code/lib/cli/src/repro-templates.ts | 12 +++++++++++ code/lib/cli/src/versions.ts | 1 + .../src/utils/get-storybook-info.ts | 1 + docs/configure/frameworks.md | 2 +- docs/frameworks.js | 2 +- 12 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 code/lib/cli/src/generators/QWIK/index.ts diff --git a/README.md b/README.md index 09db01f2fc1f..ab9c9cab4456 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ For additional help, join us in the [Storybook Discord](https://discord.gg/story | [Svelte](code/renderers/svelte) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/svelte/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/svelte-kitchen-sink/) | [![Svelte](https://img.shields.io/npm/dm/@storybook/svelte?style=flat-square&color=eee)](code/renderers/svelte) | | [Preact](code/renderers/preact) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/preact/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/preact-kitchen-sink/) | [![Preact](https://img.shields.io/npm/dm/@storybook/preact?style=flat-square&color=eee)](code/renderers/preact) | | [Marionette.js](https://github.com/storybookjs/marionette) | - | [![Marionette.js](https://img.shields.io/npm/dm/@storybook/marionette?style=flat-square&color=eee)](https://github.com/storybookjs/marionette) | +| [Qwik](https://github.com/literalpie/storybook-framework-qwik) | - | [![Qwik](https://img.shields.io/npm/dm/storybook-framework-qwik?style=flat-square&color=eee)](https://github.com/literalpie/storybook-framework-qwik) | | [Android, iOS, Flutter](https://github.com/storybookjs/native) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/native/latest?style=flat-square&color=blue&label)](https://storybookjs.github.io/native/@storybook/native-flutter-example/index.html) | [![Native](https://img.shields.io/npm/dm/@storybook/native?style=flat-square&color=eee)](https://github.com/storybookjs/native) | ### Sub Projects diff --git a/code/lib/cli/src/detect.test.ts b/code/lib/cli/src/detect.test.ts index 597e2fc7818d..533af08a65ea 100644 --- a/code/lib/cli/src/detect.test.ts +++ b/code/lib/cli/src/detect.test.ts @@ -89,6 +89,16 @@ const MOCK_FRAMEWORK_FILES: { }, }, }, + { + name: ProjectType.QWIK, + files: { + 'package.json': { + devDependencies: { + qwik: '1.0.0', + }, + }, + }, + }, { name: ProjectType.REACT_NATIVE, files: { diff --git a/code/lib/cli/src/dirs.ts b/code/lib/cli/src/dirs.ts index 69a411752360..0331f1dc79ae 100644 --- a/code/lib/cli/src/dirs.ts +++ b/code/lib/cli/src/dirs.ts @@ -1,12 +1,17 @@ import { dirname } from 'path'; import type { SupportedFrameworks, SupportedRenderers } from './project_types'; +import { externalFrameworks } from './project_types'; export function getCliDir() { return dirname(require.resolve('@storybook/cli/package.json')); } export function getRendererDir(renderer: SupportedFrameworks | SupportedRenderers) { + const externalFramework = externalFrameworks.find((framework) => framework.name === renderer); + const frameworkPackageName = externalFramework.packageName ?? `@storybook/${renderer}`; return dirname( - require.resolve(`@storybook/${renderer}/package.json`, { paths: [process.cwd()] }) + require.resolve(`${frameworkPackageName}/package.json`, { + paths: [process.cwd()], + }) ); } diff --git a/code/lib/cli/src/generators/QWIK/index.ts b/code/lib/cli/src/generators/QWIK/index.ts new file mode 100644 index 000000000000..baa3c86ac94d --- /dev/null +++ b/code/lib/cli/src/generators/QWIK/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, 'qwik', {}, 'qwik'); +}; + +export default generator; diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index bfd1ab8ac3e3..eb1bae874308 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -3,7 +3,7 @@ import fse from 'fs-extra'; import { dedent } from 'ts-dedent'; import type { NpmOptions } from '../NpmOptions'; import type { SupportedRenderers, SupportedFrameworks, Builder } from '../project_types'; -import { CoreBuilder } from '../project_types'; +import { externalFrameworks, CoreBuilder } from '../project_types'; import { getBabelDependencies, copyComponents } from '../helpers'; import { configureMain, configurePreview } from './configure'; import type { JsPackageManager } from '../js-package-manager'; @@ -41,6 +41,16 @@ const getBuilderDetails = (builder: string) => { return builder; }; +const getFrameworkPackage = (framework: string, renderer: string, builder: string) => { + const externalFramework = externalFrameworks.find( + (exFramework) => exFramework.name === framework + ); + if (externalFramework) { + return externalFramework.packageName; + } + return framework ? `@storybook/${framework}` : `@storybook/${renderer}-${builder}`; +}; + const wrapForPnp = (packageName: string) => `%%path.dirname(require.resolve(path.join('${packageName}', 'package.json')))%%`; @@ -57,9 +67,8 @@ const getFrameworkDetails = ( renderer?: string; rendererId: SupportedRenderers; } => { - const frameworkPackage = framework - ? `@storybook/${framework}` - : `@storybook/${renderer}-${builder}`; + const frameworkPackage = getFrameworkPackage(framework, renderer, builder); + const frameworkPackagePath = pnp ? wrapForPnp(frameworkPackage) : frameworkPackage; const rendererPackage = `@storybook/${renderer}`; @@ -190,7 +199,9 @@ export async function baseGenerator( .filter(Boolean) .filter( (packageToInstall) => !installedDependencies.has(getPackageDetails(packageToInstall)[0]) - ); + ) + // storybook-framework-qwik has a renderer built in + .filter((packageToInstall) => packageToInstall !== '@storybook/qwik'); const versionedPackages = await packageManager.getVersionedPackages(packages); diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index a9741facc52f..99c6daffe02d 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -26,6 +26,7 @@ import webComponentsGenerator from './generators/WEB-COMPONENTS'; import riotGenerator from './generators/RIOT'; import preactGenerator from './generators/PREACT'; import svelteGenerator from './generators/SVELTE'; +import qwikGenerator from './generators/QWIK'; import svelteKitGenerator from './generators/SVELTEKIT'; import raxGenerator from './generators/RAX'; import serverGenerator from './generators/SERVER'; @@ -104,6 +105,12 @@ const installStorybook = ( .then(commandLog('Adding Storybook support to your "React Native" app\n')); } + case ProjectType.QWIK: { + return qwikGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Qwik" app\n') + ); + } + case ProjectType.WEBPACK_REACT: return webpackReactGenerator(packageManager, npmOptions, generatorOptions).then( commandLog('Adding Storybook support to your "Webpack React" app\n') diff --git a/code/lib/cli/src/project_types.ts b/code/lib/cli/src/project_types.ts index 5de0f9c3812d..cdc369f86df5 100644 --- a/code/lib/cli/src/project_types.ts +++ b/code/lib/cli/src/project_types.ts @@ -15,8 +15,12 @@ function eqMajor(versionRange: string, major: number) { return validRange(versionRange) && minVersion(versionRange).major === major; } +export const externalFrameworks: { name: SupportedFrameworks; packageName: string }[] = [ + { name: 'qwik', packageName: 'storybook-framework-qwik' }, +]; + // Should match @storybook/ -export type SupportedFrameworks = 'nextjs' | 'angular' | 'sveltekit'; +export type SupportedFrameworks = 'nextjs' | 'angular' | 'sveltekit' | 'qwik'; // Should match @storybook/ export type SupportedRenderers = @@ -32,6 +36,7 @@ export type SupportedRenderers = | 'marko' | 'preact' | 'svelte' + | 'qwik' | 'rax' | 'aurelia' | 'html' @@ -51,6 +56,7 @@ export const SUPPORTED_RENDERERS: SupportedRenderers[] = [ 'marko', 'preact', 'svelte', + 'qwik', 'rax', 'aurelia', ]; @@ -75,6 +81,7 @@ export enum ProjectType { MARIONETTE = 'MARIONETTE', MARKO = 'MARKO', HTML = 'HTML', + QWIK = 'QWIK', RIOT = 'RIOT', PREACT = 'PREACT', SVELTE = 'SVELTE', @@ -168,6 +175,13 @@ export const supportedTemplates: TemplateConfiguration[] = [ return dependencies.every(Boolean); }, }, + { + preset: ProjectType.QWIK, + dependencies: ['@builder.io/qwik'], + matcherFunction: ({ dependencies }) => { + return dependencies.every(Boolean); + }, + }, { preset: ProjectType.REACT_PROJECT, peerDependencies: ['react'], diff --git a/code/lib/cli/src/repro-templates.ts b/code/lib/cli/src/repro-templates.ts index 999086f368a5..a363913a6444 100644 --- a/code/lib/cli/src/repro-templates.ts +++ b/code/lib/cli/src/repro-templates.ts @@ -364,6 +364,18 @@ const baseTemplates = { builder: '@storybook/builder-vite', }, }, + // NOTE: The `yarn storybook` step fails when first creating this template but manually running the command later does work + // Also, you need to remove mdx stories from main.js. + 'qwik-vite/default-ts': { + name: 'Qwik CLI (Default TS)', + script: 'yarn create qwik basic {{beforeDir}} --no-install', + inDevelopment: true, + expected: { + framework: 'storybook-framework-qwik', + renderer: 'storybook-framework-qwik', + builder: 'storybook-framework-qwik', + }, + }, } satisfies Record; /** diff --git a/code/lib/cli/src/versions.ts b/code/lib/cli/src/versions.ts index 2733c097f030..f67119038323 100644 --- a/code/lib/cli/src/versions.ts +++ b/code/lib/cli/src/versions.ts @@ -85,6 +85,7 @@ export default { '@storybook/web-components': '7.0.0-beta.26', '@storybook/web-components-webpack5': '7.0.0-beta.26', '@storybook/web-components-vite': '7.0.0-beta.26', + 'storybook-framework-qwik': '0.0.4', sb: '7.0.0-beta.26', storybook: '7.0.0-beta.26', }; 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 679ab828c03d..556d57049f00 100644 --- a/code/lib/core-common/src/utils/get-storybook-info.ts +++ b/code/lib/core-common/src/utils/get-storybook-info.ts @@ -17,6 +17,7 @@ const rendererPackages: Record = { '@storybook/riot': 'riot', '@storybook/svelte': 'svelte', '@storybook/preact': 'preact', + 'storybook-framework-qwik': 'qwik', '@storybook/rax': 'rax', '@storybook/server': 'server', }; diff --git a/docs/configure/frameworks.md b/docs/configure/frameworks.md index 9807642fffb4..079f4b3b0de4 100644 --- a/docs/configure/frameworks.md +++ b/docs/configure/frameworks.md @@ -15,7 +15,7 @@ Storybook provides support for the leading industry builders and frameworks. How | Builder | Framework | | ------- | ------------------------------------------------------------------------ | | Webpack | React, Angular, Vue, Web Components, NextJS, HTML, Ember, Preact, Svelte | -| Vite | React, Vue, Web Components, HTML, Svelte, SvelteKit | +| Vite | React, Vue, Web Components, HTML, Svelte, SvelteKit, Qwik | ## Configure diff --git a/docs/frameworks.js b/docs/frameworks.js index ce957e01d08b..f37ffd6cd8cc 100644 --- a/docs/frameworks.js +++ b/docs/frameworks.js @@ -1,6 +1,6 @@ module.exports = { coreFrameworks: ['react', 'vue', 'angular', 'web-components'], - communityFrameworks: ['ember', 'html', 'svelte', 'preact'], + communityFrameworks: ['ember', 'html', 'svelte', 'preact', 'qwik'], featureGroups: [ { name: 'Essentials',