diff --git a/.circleci/config.yml b/.circleci/config.yml index e124f267f1ba..f67b712e04df 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -836,19 +836,19 @@ workflows: requires: - unit-tests - create-sandboxes: - parallelism: 13 + parallelism: 14 requires: - build - build-sandboxes: - parallelism: 13 + parallelism: 14 requires: - create-sandboxes - chromatic-sandboxes: - parallelism: 10 + parallelism: 11 requires: - build-sandboxes - e2e-production: - parallelism: 8 + parallelism: 9 requires: - build-sandboxes - e2e-dev: @@ -856,7 +856,7 @@ workflows: requires: - create-sandboxes - test-runner-production: - parallelism: 8 + parallelism: 9 requires: - build-sandboxes - vitest-integration: @@ -912,19 +912,19 @@ workflows: requires: - unit-tests - create-sandboxes: - parallelism: 19 + parallelism: 20 requires: - build - build-sandboxes: - parallelism: 19 + parallelism: 20 requires: - create-sandboxes - chromatic-sandboxes: - parallelism: 16 + parallelism: 17 requires: - build-sandboxes - e2e-production: - parallelism: 14 + parallelism: 15 requires: - build-sandboxes - e2e-dev: @@ -932,7 +932,7 @@ workflows: requires: - create-sandboxes - test-runner-production: - parallelism: 14 + parallelism: 15 requires: - build-sandboxes - vitest-integration: @@ -986,22 +986,22 @@ workflows: requires: - build - create-sandboxes: - parallelism: 36 + parallelism: 37 requires: - build # - smoke-test-sandboxes: # disabled for now # requires: # - create-sandboxes - build-sandboxes: - parallelism: 36 + parallelism: 37 requires: - create-sandboxes - chromatic-sandboxes: - parallelism: 33 + parallelism: 34 requires: - build-sandboxes - e2e-production: - parallelism: 31 + parallelism: 32 requires: - build-sandboxes - e2e-dev: @@ -1009,7 +1009,7 @@ workflows: requires: - create-sandboxes - test-runner-production: - parallelism: 31 + parallelism: 32 requires: - build-sandboxes - vitest-integration: diff --git a/code/core/scripts/helpers/sourcefiles.ts b/code/core/scripts/helpers/sourcefiles.ts index 2f437961a91e..e7a5394cb9b7 100644 --- a/code/core/scripts/helpers/sourcefiles.ts +++ b/code/core/scripts/helpers/sourcefiles.ts @@ -2,6 +2,7 @@ import { readdir, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { GlobalRegistrator } from '@happy-dom/global-registrator'; +import { isNotNil } from 'es-toolkit'; import { dedent, esbuild, getWorkspace, prettier } from '../../../../scripts/prepare/tools'; import { temporaryFile } from '../../src/common/utils/cli'; @@ -26,7 +27,7 @@ export const generateSourceFiles = async () => { async function generateVersionsFile(prettierConfig: prettier.Options | null): Promise { const location = join(__dirname, '..', '..', 'src', 'common', 'versions.ts'); - const workspace = await getWorkspace(); + const workspace = (await getWorkspace()).filter(isNotNil); const versions = JSON.stringify( workspace @@ -55,7 +56,7 @@ async function generateVersionsFile(prettierConfig: prettier.Options | null): Pr } async function generateFrameworksFile(prettierConfig: prettier.Options | null): Promise { - const thirdPartyFrameworks = ['qwik', 'solid', 'react-rsbuild', 'vue3-rsbuild']; + const thirdPartyFrameworks = ['qwik', 'solid', 'nuxt', 'react-rsbuild', 'vue3-rsbuild']; const location = join(__dirname, '..', '..', 'src', 'types', 'modules', 'frameworks.ts'); const frameworksDirectory = join(__dirname, '..', '..', '..', 'frameworks'); diff --git a/code/core/src/cli/detect.test.ts b/code/core/src/cli/detect.test.ts index ea7f8139fda3..409cf92effa7 100644 --- a/code/core/src/cli/detect.test.ts +++ b/code/core/src/cli/detect.test.ts @@ -43,6 +43,28 @@ const MOCK_FRAMEWORK_FILES: { }, }, }, + { + name: ProjectType.NUXT, + files: { + 'package.json': { + dependencies: { + nuxt: '^3.11.2', + }, + }, + }, + }, + { + name: ProjectType.NUXT, + files: { + 'package.json': { + dependencies: { + // Nuxt projects may have Vue 3 as an explicit dependency + nuxt: '^3.11.2', + vue: '^3.0.0', + }, + }, + }, + }, { name: ProjectType.VUE3, files: { @@ -435,16 +457,6 @@ describe('Detect', () => { expect(result).toBe(ProjectType.UNDETECTED); }); - // TODO(blaine): Remove once Nuxt3 is supported - it(`UNSUPPORTED for Nuxt framework above version 3.0.0`, () => { - const result = detectFrameworkPreset({ - dependencies: { - nuxt: '3.0.0', - }, - }); - expect(result).toBe(ProjectType.UNSUPPORTED); - }); - // TODO: The mocking in this test causes tests after it to fail it('REACT_SCRIPTS for custom react scripts config', () => { const forkedReactScriptsConfig = { diff --git a/code/core/src/cli/detect.ts b/code/core/src/cli/detect.ts index 5b50abee4301..a771f6476f8c 100644 --- a/code/core/src/cli/detect.ts +++ b/code/core/src/cli/detect.ts @@ -123,7 +123,11 @@ export async function detectBuilder(packageManager: JsPackageManager, projectTyp } // REWORK - if (webpackConfig || (dependencies.webpack && dependencies.vite !== undefined)) { + if ( + webpackConfig || + ((dependencies.webpack || dependencies['@nuxt/webpack-builder']) && + dependencies.vite !== undefined) + ) { commandLog('Detected webpack project. Setting builder to webpack')(); return CoreBuilder.Webpack5; } @@ -138,6 +142,8 @@ export async function detectBuilder(packageManager: JsPackageManager, projectTyp case ProjectType.NEXTJS: case ProjectType.EMBER: return CoreBuilder.Webpack5; + case ProjectType.NUXT: + return CoreBuilder.Vite; default: const { builder } = await prompts( { @@ -207,6 +213,13 @@ export async function detectLanguage(packageManager: JsPackageManager) { } else if (semver.lt(typescriptVersion, '3.8.0')) { logger.warn('Detected TypeScript < 3.8, populating with JavaScript examples'); } + } else { + // No direct dependency on TypeScript, but could be a transitive dependency + // This is eg the case for Nuxt projects, which support a recent version of TypeScript + // Check for tsconfig.json (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) + if (existsSync('tsconfig.json')) { + language = SupportedLanguage.TYPESCRIPT_4_9; + } } return language; diff --git a/code/core/src/cli/dirs.ts b/code/core/src/cli/dirs.ts index 11ca9cb67441..6e6867e38d57 100644 --- a/code/core/src/cli/dirs.ts +++ b/code/core/src/cli/dirs.ts @@ -40,7 +40,7 @@ export async function getRendererDir( ) { const externalFramework = externalFrameworks.find((framework) => framework.name === renderer); const frameworkPackageName = - externalFramework?.renderer || externalFramework?.packageName || `@storybook/${renderer}`; + externalFramework?.packageName || externalFramework?.renderer || `@storybook/${renderer}`; const packageJsonPath = join(frameworkPackageName, 'package.json'); diff --git a/code/core/src/cli/helpers.ts b/code/core/src/cli/helpers.ts index 27e91f001ac1..d5ebb9b65a2d 100644 --- a/code/core/src/cli/helpers.ts +++ b/code/core/src/cli/helpers.ts @@ -153,6 +153,7 @@ export const frameworkToDefaultBuilder: Record< 'html-vite': CoreBuilder.Vite, 'html-webpack5': CoreBuilder.Webpack5, nextjs: CoreBuilder.Webpack5, + nuxt: CoreBuilder.Vite, 'experimental-nextjs-vite': CoreBuilder.Vite, 'preact-vite': CoreBuilder.Vite, 'preact-webpack5': CoreBuilder.Webpack5, diff --git a/code/core/src/cli/project_types.ts b/code/core/src/cli/project_types.ts index 25148d2bc089..d9ca64e25345 100644 --- a/code/core/src/cli/project_types.ts +++ b/code/core/src/cli/project_types.ts @@ -1,5 +1,5 @@ import type { - SupportedRenderers as CoreSupportedFrameworks, + SupportedRenderers as CoreSupportedRenderers, SupportedFrameworks, } from '@storybook/core/types'; @@ -24,10 +24,16 @@ export type ExternalFramework = { export const externalFrameworks: ExternalFramework[] = [ { name: 'qwik', packageName: 'storybook-framework-qwik' }, { name: 'solid', frameworks: ['storybook-solidjs-vite'], renderer: 'storybook-solidjs' }, + { + name: 'nuxt', + packageName: '@storybook-vue/nuxt', + frameworks: ['@storybook-vue/nuxt'], + renderer: '@storybook/vue3', + }, ]; -/** @deprecated Please use `SupportedFrameworks` from `@storybook/types` instead */ -export type SupportedRenderers = CoreSupportedFrameworks; +/** @deprecated Please use `SupportedRenderers` from `@storybook/types` instead */ +export type SupportedRenderers = CoreSupportedRenderers; export const SUPPORTED_RENDERERS: SupportedRenderers[] = [ 'react', @@ -52,6 +58,7 @@ export enum ProjectType { WEBPACK_REACT = 'WEBPACK_REACT', NEXTJS = 'NEXTJS', VUE3 = 'VUE3', + NUXT = 'NUXT', ANGULAR = 'ANGULAR', EMBER = 'EMBER', WEB_COMPONENTS = 'WEB_COMPONENTS', @@ -121,6 +128,13 @@ export type TemplateConfiguration = { * specific. */ export const supportedTemplates: TemplateConfiguration[] = [ + { + preset: ProjectType.NUXT, + dependencies: ['nuxt'], + matcherFunction: ({ dependencies }) => { + return dependencies?.every(Boolean) ?? true; + }, + }, { preset: ProjectType.VUE3, dependencies: { @@ -242,10 +256,7 @@ export const supportedTemplates: TemplateConfiguration[] = [ // users an "Unsupported framework" message export const unsupportedTemplate: TemplateConfiguration = { preset: ProjectType.UNSUPPORTED, - dependencies: { - // TODO(blaine): Remove when we support Nuxt 3 - nuxt: (versionRange) => eqMajor(versionRange, 3), - }, + dependencies: {}, matcherFunction: ({ dependencies }) => { return dependencies?.some(Boolean) ?? false; }, diff --git a/code/core/src/common/utils/framework-to-renderer.ts b/code/core/src/common/utils/framework-to-renderer.ts index 7ae4c3b057a5..72cb4c1e2484 100644 --- a/code/core/src/common/utils/framework-to-renderer.ts +++ b/code/core/src/common/utils/framework-to-renderer.ts @@ -24,6 +24,7 @@ export const frameworkToRenderer: Record< sveltekit: 'svelte', 'vue3-vite': 'vue3', 'vue3-webpack5': 'vue3', + nuxt: 'vue3', 'web-components-vite': 'web-components', 'web-components-webpack5': 'web-components', 'react-rsbuild': 'react', diff --git a/code/core/src/types/modules/frameworks.ts b/code/core/src/types/modules/frameworks.ts index e3e1b6383a7f..8e0ec1a7eea0 100644 --- a/code/core/src/types/modules/frameworks.ts +++ b/code/core/src/types/modules/frameworks.ts @@ -21,5 +21,6 @@ export type SupportedFrameworks = | 'web-components-webpack5' | 'qwik' | 'solid' + | 'nuxt' | 'react-rsbuild' | 'vue3-rsbuild'; diff --git a/code/core/src/types/modules/renderers.ts b/code/core/src/types/modules/renderers.ts index 4fcf0be99d87..e6fd0f650bf3 100644 --- a/code/core/src/types/modules/renderers.ts +++ b/code/core/src/types/modules/renderers.ts @@ -11,4 +11,5 @@ export type SupportedRenderers = | 'html' | 'web-components' | 'server' - | 'solid'; + | 'solid' + | 'nuxt'; diff --git a/code/e2e-tests/addon-docs.spec.ts b/code/e2e-tests/addon-docs.spec.ts index 54c046a8aec7..6d0542bf4b8d 100644 --- a/code/e2e-tests/addon-docs.spec.ts +++ b/code/e2e-tests/addon-docs.spec.ts @@ -191,7 +191,7 @@ test.describe('addon-docs', () => { test('should resolve react to the correct version', async ({ page }) => { test.skip( - templateName?.includes('nextjs'), + templateName?.includes('nextjs') || templateName?.includes('nuxt'), 'TODO: remove this once sandboxes are synced (SOON!!)' ); // Arrange - Navigate to MDX docs diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index f905d2841803..26ce0de96aa4 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -400,6 +400,16 @@ const baseTemplates = { }, skipTasks: ['e2e-tests-dev', 'bench'], }, + 'nuxt-vite/default-ts': { + name: 'Nuxt v3 (Vite | TypeScript)', + script: 'npx nuxi init --packageManager yarn --gitInit false {{beforeDir}}', + expected: { + framework: '@storybook-vue/nuxt', + renderer: '@storybook/vue3', + builder: '@storybook/builder-vite', + }, + skipTasks: ['e2e-tests-dev', 'bench', 'vitest-integration'], + }, 'html-webpack/default': { name: 'HTML Latest (Webpack | JavaScript)', script: 'yarn create webpack5-html {{beforeDir}}', @@ -809,6 +819,7 @@ export const normal: TemplateKey[] = [ 'react-vite/default-ts', 'angular-cli/default-ts', 'vue3-vite/default-ts', + 'nuxt-vite/default-ts', 'lit-vite/default-ts', 'svelte-vite/default-ts', 'svelte-kit/skeleton-ts', diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index 765a06c1f3d6..d774e855fc44 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -311,7 +311,8 @@ ], "scripts": { "check": "jiti ../../../scripts/prepare/check.ts", - "prep": "jiti ../../../scripts/prepare/bundle.ts" + "prep": "jiti ../../../scripts/prepare/bundle.ts", + "sb": "node ./bin/index.js" }, "dependencies": { "@storybook/core": "workspace:*" diff --git a/code/lib/create-storybook/src/generators/NUXT/index.ts b/code/lib/create-storybook/src/generators/NUXT/index.ts new file mode 100644 index 000000000000..a7d7be640eb7 --- /dev/null +++ b/code/lib/create-storybook/src/generators/NUXT/index.ts @@ -0,0 +1,31 @@ +import { baseGenerator } from '../baseGenerator'; +import type { Generator } from '../types'; + +const generator: Generator = async (packageManager, npmOptions, options) => { + await baseGenerator( + packageManager, + npmOptions, + options, + 'vue3', + { + extraPackages: async () => { + return ['@nuxtjs/storybook']; + }, + installFrameworkPackages: false, + componentsDestinationPath: './components', + extraMain: { + stories: ['../components/**/*.mdx', '../components/**/*.stories.@(js|jsx|ts|tsx|mdx)'], + }, + }, + 'nuxt' + ); + // Add nuxtjs/storybook to nuxt.config.js + await packageManager.runPackageCommand('nuxi', [ + 'module', + 'add', + '@nuxtjs/storybook', + '--skipInstall', + ]); +}; + +export default generator; diff --git a/code/lib/create-storybook/src/generators/baseGenerator.ts b/code/lib/create-storybook/src/generators/baseGenerator.ts index 84daecba1b46..1b0c917edd58 100644 --- a/code/lib/create-storybook/src/generators/baseGenerator.ts +++ b/code/lib/create-storybook/src/generators/baseGenerator.ts @@ -1,14 +1,14 @@ import { mkdir } from 'node:fs/promises'; import { dirname, join } from 'node:path'; -import type { NpmOptions } from 'storybook/internal/cli'; -import type { Builder, SupportedRenderers } from 'storybook/internal/cli'; +import type { Builder, NpmOptions } from 'storybook/internal/cli'; import { SupportedLanguage, externalFrameworks } from 'storybook/internal/cli'; import { copyTemplateFiles } from 'storybook/internal/cli'; import { configureEslintPlugin, extractEslintInfo } from 'storybook/internal/cli'; import { detectBuilder } from 'storybook/internal/cli'; import type { JsPackageManager } from 'storybook/internal/common'; import { getPackageDetails, versions as packageVersions } from 'storybook/internal/common'; +import type { SupportedRenderers } from 'storybook/internal/types'; import type { SupportedFrameworks } from 'storybook/internal/types'; // eslint-disable-next-line depend/ban-dependencies @@ -27,6 +27,7 @@ const defaultOptions: FrameworkOptions = { staticDir: undefined, addScripts: true, addMainFile: true, + addPreviewFile: true, addComponents: true, webpackCompiler: () => undefined, extraMain: undefined, @@ -34,6 +35,7 @@ const defaultOptions: FrameworkOptions = { extensions: undefined, componentsDestinationPath: undefined, storybookConfigFolder: '.storybook', + installFrameworkPackages: true, }; const getBuilderDetails = (builder: string) => { @@ -82,13 +84,10 @@ const getFrameworkPackage = (framework: string | undefined, renderer: string, bu ); } - if (externalFramework.frameworks !== undefined) { - return externalFramework.frameworks.find((item) => - item.match(new RegExp(`-${storybookBuilder}`)) - ); - } - - return externalFramework.packageName; + return ( + externalFramework.frameworks?.find((item) => item.match(new RegExp(`-${storybookBuilder}`))) ?? + externalFramework.packageName + ); }; const getRendererPackage = (framework: string | undefined, renderer: string) => { @@ -117,6 +116,7 @@ const getFrameworkDetails = ( framework?: string; renderer?: string; rendererId: SupportedRenderers; + frameworkPackage?: string; } => { const frameworkPackage = getFrameworkPackage(framework, renderer, builder); invariant(frameworkPackage, 'Missing framework package.'); @@ -144,6 +144,7 @@ const getFrameworkDetails = ( return { packages: [rendererPackage, frameworkPackage], framework: frameworkPackagePath, + frameworkPackage, rendererId: renderer, type: 'framework', }; @@ -169,8 +170,18 @@ const stripVersions = (addons: string[]) => addons.map((addon) => getPackageDeta const hasInteractiveStories = (rendererId: SupportedRenderers) => ['react', 'angular', 'preact', 'svelte', 'vue3', 'html', 'solid', 'qwik'].includes(rendererId); -const hasFrameworkTemplates = (framework?: SupportedFrameworks) => - framework ? ['angular', 'nextjs', 'react-native-web-vite'].includes(framework) : false; +const hasFrameworkTemplates = (framework?: SupportedFrameworks) => { + if (!framework) { + return false; + } + // Nuxt has framework templates, but for sandboxes we create them from the Vue3 renderer + // As the Nuxt framework templates are not compatible with the stories we need for CI. + // See: https://github.com/storybookjs/storybook/pull/28607#issuecomment-2467903327 + if (framework === 'nuxt') { + return process.env.IN_STORYBOOK_SANDBOX !== 'true'; + } + return ['angular', 'nextjs', 'react-native-web-vite'].includes(framework); +}; export async function baseGenerator( packageManager: JsPackageManager, @@ -193,6 +204,7 @@ export async function baseGenerator( rendererId, framework: frameworkInclude, builder: builderInclude, + frameworkPackage, } = getFrameworkDetails( renderer, builder, @@ -208,12 +220,14 @@ export async function baseGenerator( staticDir, addScripts, addMainFile, + addPreviewFile, addComponents, extraMain, extensions, storybookConfigFolder, componentsDestinationPath, webpackCompiler, + installFrameworkPackages, } = { ...defaultOptions, ...options, @@ -278,7 +292,7 @@ export async function baseGenerator( const allPackages = [ 'storybook', getExternalFramework(rendererId) ? undefined : `@storybook/${rendererId}`, - ...frameworkPackages, + ...(installFrameworkPackages ? frameworkPackages : []), ...addonPackages, ...(extraPackagesToInstall || []), ].filter(Boolean); @@ -320,9 +334,9 @@ export async function baseGenerator( addDependenciesSpinner.succeed(); } - // Passing `recursive: true` ensures that the method doesn't throw when - // the directory already exists. - await mkdir(`./${storybookConfigFolder}`, { recursive: true }); + if (addMainFile || addPreviewFile) { + await mkdir(`./${storybookConfigFolder}`, { recursive: true }); + } if (addMainFile) { const prefixes = shouldApplyRequireWrapperOnPackageNames @@ -351,6 +365,7 @@ export async function baseGenerator( name: frameworkInclude, options: options.framework || {}, }, + frameworkPackage, prefixes, storybookConfigFolder, addons: shouldApplyRequireWrapperOnPackageNames @@ -370,12 +385,14 @@ export async function baseGenerator( }); } - await configurePreview({ - frameworkPreviewParts, - storybookConfigFolder: storybookConfigFolder as string, - language, - rendererId, - }); + if (addPreviewFile) { + await configurePreview({ + frameworkPreviewParts, + storybookConfigFolder: storybookConfigFolder as string, + language, + rendererId, + }); + } if (addScripts) { await packageManager.addStorybookCommandInScripts({ diff --git a/code/lib/create-storybook/src/generators/configure.test.ts b/code/lib/create-storybook/src/generators/configure.test.ts index 853e1102a055..e593810dd971 100644 --- a/code/lib/create-storybook/src/generators/configure.test.ts +++ b/code/lib/create-storybook/src/generators/configure.test.ts @@ -26,6 +26,7 @@ describe('configureMain', () => { framework: { name: '@storybook/react-vite', }, + frameworkPackage: '@storybook/react-vite', }); const { calls } = vi.mocked(fsp.writeFile).mock; @@ -55,6 +56,7 @@ describe('configureMain', () => { framework: { name: '@storybook/react-vite', }, + frameworkPackage: '@storybook/react-vite', }); const { calls } = vi.mocked(fsp.writeFile).mock; @@ -89,6 +91,7 @@ describe('configureMain', () => { framework: { name: "%%path.dirname(require.resolve(path.join('@storybook/react-webpack5', 'package.json')))%%", }, + frameworkPackage: '@storybook/react-webpack5', }); const { calls } = vi.mocked(fsp.writeFile).mock; diff --git a/code/lib/create-storybook/src/generators/configure.ts b/code/lib/create-storybook/src/generators/configure.ts index c7002c58c045..401509dc2399 100644 --- a/code/lib/create-storybook/src/generators/configure.ts +++ b/code/lib/create-storybook/src/generators/configure.ts @@ -13,6 +13,7 @@ interface ConfigureMainOptions { storybookConfigFolder: string; language: SupportedLanguage; prefixes: string[]; + frameworkPackage: string; /** * Extra values for main.js * @@ -61,6 +62,7 @@ export async function configureMain({ extensions = ['js', 'jsx', 'mjs', 'ts', 'tsx'], storybookConfigFolder, language, + frameworkPackage, prefixes = [], ...custom }: ConfigureMainOptions) { @@ -78,8 +80,6 @@ export async function configureMain({ let mainConfigTemplate = dedent`<><>const config<> = <>; export default config;`; - const frameworkPackage = sanitizeFramework(custom.framework?.name); - if (!frameworkPackage) { mainConfigTemplate = mainConfigTemplate.replace('<>', '').replace('<>', ''); logger.warn('Could not find framework package name'); diff --git a/code/lib/create-storybook/src/generators/types.ts b/code/lib/create-storybook/src/generators/types.ts index e9192a47c3c9..3c07d97e27cc 100644 --- a/code/lib/create-storybook/src/generators/types.ts +++ b/code/lib/create-storybook/src/generators/types.ts @@ -23,6 +23,7 @@ export interface FrameworkOptions { staticDir?: string; addScripts?: boolean; addMainFile?: boolean; + addPreviewFile?: boolean; addComponents?: boolean; webpackCompiler?: ({ builder }: { builder: Builder }) => 'babel' | 'swc' | undefined; extraMain?: any; @@ -30,6 +31,7 @@ export interface FrameworkOptions { framework?: Record; storybookConfigFolder?: string; componentsDestinationPath?: string; + installFrameworkPackages?: boolean; } export type Generator = ( diff --git a/code/lib/create-storybook/src/initiate.ts b/code/lib/create-storybook/src/initiate.ts index 6c1c6559d262..970cef3d137b 100644 --- a/code/lib/create-storybook/src/initiate.ts +++ b/code/lib/create-storybook/src/initiate.ts @@ -27,6 +27,7 @@ import angularGenerator from './generators/ANGULAR'; import emberGenerator from './generators/EMBER'; import htmlGenerator from './generators/HTML'; import nextjsGenerator from './generators/NEXTJS'; +import nuxtGenerator from './generators/NUXT'; import preactGenerator from './generators/PREACT'; import qwikGenerator from './generators/QWIK'; import reactGenerator from './generators/REACT'; @@ -117,6 +118,11 @@ const installStorybook = async ( commandLog('Adding Storybook support to your "Vue 3" app') ); + case ProjectType.NUXT: + return nuxtGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Nuxt" app') + ); + case ProjectType.ANGULAR: commandLog('Adding Storybook support to your "Angular" app'); return angularGenerator(packageManager, npmOptions, generatorOptions, options); diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 1c5618453696..2f00de2a3090 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -42,7 +42,7 @@ const sbInit = async ( debug?: boolean ) => { const sbCliBinaryPath = join(__dirname, `../../code/lib/create-storybook/bin/index.cjs`); - console.log(`🎁 Installing storybook`); + console.log(`🎁 Installing Storybook`); const env = { STORYBOOK_DISABLE_TELEMETRY: 'true', ...envVars }; const fullFlags = ['--yes', ...(flags || [])]; await runCommand(`${sbCliBinaryPath} ${fullFlags.join(' ')}`, { cwd, env }, debug); diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index ea99a566dbef..96db4f1b9f77 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -245,7 +245,19 @@ function addEsbuildLoaderToStories(mainConfig: ConfigFile) { And allow source directories to complement any existing allow patterns (".storybook" is already being allowed by builder-vite) */ -function setSandboxViteFinal(mainConfig: ConfigFile) { +function setSandboxViteFinal(mainConfig: ConfigFile, template: TemplateKey) { + const temporaryAliasWorkaround = template.includes('nuxt') + ? ` + // TODO: Remove this once Storybook Nuxt applies this internally + resolve: { + ...config.resolve, + alias: { + ...config.resolve.alias, + vue: 'vue/dist/vue.esm-bundler.js', + } + } + ` + : ''; const viteFinalCode = ` (config) => ({ ...config, @@ -257,6 +269,7 @@ function setSandboxViteFinal(mainConfig: ConfigFile) { allow: ['stories', 'src', 'template-stories', 'node_modules', ...(config.server?.fs?.allow || [])], }, }, + ${temporaryAliasWorkaround} })`; // @ts-expect-error (Property 'expression' does not exist on type 'BlockStatement') mainConfig.setFieldNode(['viteFinal'], babelParse(viteFinalCode).program.body[0].expression); @@ -566,9 +579,10 @@ export const addStories: Task['run'] = async ( { sandboxDir, template, key }, { addon: extraAddons, disableDocs } ) => { - logger.log('💃 adding stories'); + logger.log('💃 Adding stories'); const cwd = sandboxDir; - const storiesPath = await findFirstPath([join('src', 'stories'), 'stories'], { cwd }); + const storiesPath = + (await findFirstPath([join('src', 'stories'), 'stories'], { cwd })) || 'stories'; const mainConfig = await readConfig({ fileName: 'main', cwd }); const packageManager = JsPackageManagerFactory.getPackageManager({}, sandboxDir); @@ -799,7 +813,7 @@ export const extendMain: Task['run'] = async ({ template, sandboxDir, key }, { d } if (template.expected.builder === '@storybook/builder-vite') { - setSandboxViteFinal(mainConfig); + setSandboxViteFinal(mainConfig, key); } await writeConfig(mainConfig); }; diff --git a/scripts/utils/yarn.ts b/scripts/utils/yarn.ts index 8013083bc2a6..2aeeaada2edf 100644 --- a/scripts/utils/yarn.ts +++ b/scripts/utils/yarn.ts @@ -121,6 +121,8 @@ export const configureYarn2ForVerdaccio = async ({ command.push( `yarn config set logFilters --json '[ { "code": "YN0013", "level": "discard" } ]'` ); + } else if (key.includes('nuxt')) { + // Nothing to do for Nuxt } else { // Discard all YN0013 - FETCH_NOT_CACHED messages // Error on YN0060 - INCOMPATIBLE_PEER_DEPENDENCY