Skip to content

Conversation

@valentinpalkovic
Copy link
Contributor

@valentinpalkovic valentinpalkovic commented Oct 13, 2025

Closes #25389
Closes #32043
Closes #32778
Closes #31880
Closes #31914

What I did

This PR represents a massive refactor and modernization of the Storybook CLI, primarily focused on the init command. The original initiate.ts file, a monolithic, 900+ line behemoth, was brittle, hard to maintain, and difficult to test.

This new architecture replaces it with a clean, command-based pipeline that is modular, testable, and far more extensible. We've also swapped our CLI's user interface from prompts to @clack/prompts, providing a significantly improved, modern, and interactive experience for users.

Highlights of the Change

Command-Based init Workflow: The entire init process is now orchestrated as a series of discrete, testable commands:

  • PreflightCheckCommand: Handles empty directory scaffolding and package manager setup.
  • ProjectDetectionCommand: Detects the project type (e.g., React, Angular).
  • FrameworkDetectionCommand: Determines the correct Storybook framework, builder, and renderer.
  • UserPreferencesCommand: Handles all user interaction (New user? Install type?).
  • GeneratorExecutionCommand: Runs the appropriate framework-specific generator.
  • DependencyInstallationCommand: Collects all dependencies and installs them in a single step.
  • AddonConfigurationCommand: Runs post-install configuration for addons like a11y and vitest.
  • FinalizationCommand: Updates .gitignore and prints success messages.

New Generator System:
Introduced a generatorRegistry and a new GeneratorModule interface.

All framework generators (React, Angular, Next.js, Nuxt, etc.) have been refactored to this new, modular standard, separating metadata and configuration logic .

Modern Clack UI:

  • Replaced prompts, ora, and boxen with @clack/prompts across the entire CLI (init, add, upgrade, automigrate) for a unified, beautiful, and interactive experience.

Centralized Addon & Feature Logic:

  • AddonVitestService: A new, centralized service that manages all logic for the test feature. It handles compatibility validation, dependency collection, and configuration, ensuring logic is no longer duplicated between init and add .
  • DependencyCollector: A new class that gathers all required dependencies before installation, allowing us to run a single npm install/yarn add at the end of the init process .

a11y in recommended:
The test feature now also includes @storybook/addon-a11y by default, as it's a prerequisite for accessibility testing.

New Next.js-Vite Support:

  • The Next.js generator now defaults to @storybook/nextjs-vite (Vite builder) for new projects. It intelligently detects custom webpack.config.js or .babelrc files and prompts the user to fall back to @storybook/nextjs (Webpack 5) if needed.

  • Added a new nextjs-to-nextjs-vite automigration to help users move from the old Webpack-based setup .

Rsbuild Support during initialization:

  • When initializing Storybook in an rsbuild-based project, we will set up your project properly if rsbuild is used with one of the supported renderers: lit, react, vue, vanilla js.

Enhanced Logging & Error Handling:

  • All CLI commands now use the standardized logger and prompt from node-logger.
  • Builder output (Vite) is now prefixed for clarity (e.g., [Vite] ...). Webpack was not adjusted yet due to its complex nature of logging items (status)
  • All CLI commands (init, add, automigrate) will now reliably generate a debug-storybook.log file on failure, making debugging much easier.

Introduced new StorybookError subclasses for CLI failures (e.g., AddonVitestPostinstallError)

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This is a massive change. Please test the init and add commands thoroughly.

storybook init

  1. The "Golden Path":
  • cd into a new React + Vite project.
  • Run npx storybook@<canary> init.
  • ✅ Assert: You see the new Clack UI.
  • ✅ Assert: You are prompted "New to Storybook?" > "What configuration?". Select "Recommended".
  • ✅ Assert: It installs all recommended dependencies, including test (@storybook/addon-vitest, vitest, etc.) and a11y (@storybook/addon-a11y).
  • ✅ Assert: It prompts you to install Playwright binaries.
  • ✅ Assert: The final success message lists docs, test, a11y, onboarding.
  1. Non-Interactive (--yes):
  • cd into a new React + Vite project.
  • Run npx storybook@<canary> init --yes.
  • ✅ Assert: No prompts appear.
  • ✅ Assert: The result is identical to the "Recommended" install (all features included).
  1. Feature Selection:
  • cd into a new React + Vite project.
  • Run npx storybook@latest init --features docs a11y.
  • ✅ Assert: No prompts for "New User" or "Install Type" appear.
  • ✅ Assert: Only @storybook/addon-docs and @storybook/addon-a11y are installed. @storybook/addon-vitest and @storybook/addon-onboarding are not installed.
  1. Next.js (Vite vs. Webpack):
  • cd into a clean Next.js project. Run init --yes.
  • ✅ Assert: It installs @storybook/nextjs-vite and vite.
  • Now, rm -rf .storybook and add a webpack(config) { return config; } block to next.config.js.
  • Run init interactively.
  • ✅ Assert: It must prompt you to choose between @storybook/nextjs-vite (default) and @storybook/nextjs (Webpack).

storybook add

  • cd into a project without the test feature (e.g., init --features docs).
  • Run npx storybook@<canary> add @storybook/addon-vitest.
  • ✅ Assert: The postinstall script runs.
  • ✅ Assert: You see the Clack UI prompt to install Playwright.
  • ✅ Assert: It creates vitest.config.ts.
  • ✅ Assert: If you also have addon-a11y installed, it should run the a11y-addon-test automigration to configure it.

storybook automigrate

  • cd into a project using the old @storybook/nextjs (Webpack).
  • Run npx storybook@latest automigrate nextjs-to-nextjs-vite.
  • ✅ Assert: package.json and main.ts are updated from @storybook/nextjs to @storybook/nextjs-vite.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-32717-sha-7a16d827. Try it out in a new sandbox by running npx [email protected] sandbox or in an existing project with npx [email protected] upgrade.

More information
Published version 0.0.0-pr-32717-sha-7a16d827
Triggered by @valentinpalkovic
Repository storybookjs/storybook
Branch valentin/cli-init-rework
Commit 7a16d827
Datetime Wed Nov 19 10:25:34 UTC 2025 (1763547934)
Workflow run 19498001525

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=32717

Summary by CodeRabbit

  • New Features

    • Modular init flow with pluggable generators and a dedicated addon-configuration command.
  • Improvements

    • CLI: new --logfile and --loglevel options; "a11y" added to feature choices.
    • Smoother, more consistent logging and prompt UX across init, sandbox, and dev workflows.
    • Better automated handling for test integrations and dependency setup during initialization.
  • Tests

    • Broader test coverage for init, generators, package managers, and migrations.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

📝 Walkthrough

Walkthrough

Modularized create/init flows, centralized command execution and logging/prompting, consolidated mocking utilities, introduced typed enums (frameworks, renderers, builders, features, languages, project types), reworked generator and command modules, refactored Vitest addon/postinstall and builder mocking integrations, and updated CI test-init features to include a11y.

Changes

Cohort / File(s) Summary
CI config
.circleci/config.yml, .circleci/src/jobs/test-init-features.yml
test-init-features changed Storybook init features to docs test a11y and sets --loglevel=debug.
Create-storybook & init orchestration
code/lib/create-storybook/src/bin/run.ts, code/lib/create-storybook/src/initiate.ts, code/lib/create-storybook/src/commands/*, code/lib/create-storybook/src/commands/index.ts
Large refactor: split init into command modules (Preflight, ProjectDetection, FrameworkDetection, UserPreferences, GeneratorExecution, DependencyInstallation, AddonConfiguration, Finalization), telemetry wrappers, logfile/loglevel CLI options, many new command implementations and tests.
Generators & registry
code/lib/create-storybook/src/generators/**, .../modules/GeneratorModule.ts, .../GeneratorRegistry.ts, .../registerGenerators.ts, .../types.ts
Convert generators to module form via defineGeneratorModule({ metadata, configure, postConfigure }); add GeneratorRegistry; change GeneratorOptions (features → Set, add DependencyCollector) and related public types.
Dependency collection & installation
code/lib/create-storybook/src/dependency-collector.ts, .../DependencyInstallationCommand.ts, .../AddonConfigurationCommand.ts, .../FinalizationCommand.ts
Add DependencyCollector, dependency-install and addon-configuration commands, FinalizationCommand, ErrorCollector integration, and tests.
Node logger, prompts & tasks
code/core/src/node-logger/**, code/core/src/core-server/*
Introduce ConsoleLogger/StyledConsoleLogger, refactor logTracker (writeToFile/shouldWriteLogsToFile), adopt clack-only prompt provider, add taskLog.group, BoxOptions/logBox, and switch many logs to logger.step/intro/outro.
Command execution util & package managers
code/core/src/common/utils/command.ts, code/core/src/common/js-package-manager/*, *Proxy.ts
Add centralized execa-backed executeCommand/executeCommandSync/executeNodeCommand; change runPackageCommand to options-object { args, ... }; introduce PackageManagerName enum, package.json caching, update proxies/tests.
Mocking-utils consolidation
code/core/src/mocking-utils/*, code/core/build-config.ts, builders' plugins/loaders
Consolidate automock/extract/resolve/esmWalker/runtime into internal/mocking-utils; add getMockerRuntime; change signatures (extractMockCalls, resolveMock) to accept findMockRedirect; update builders/loaders to import new APIs.
Builders — Vite
code/builders/builder-vite/src/{logger,build,vite-server,preset,index}.ts, code/builders/builder-vite/package.json, code/builders/builder-vite/preset.js
Add createViteLogger and assign to Vite customLogger; add corePresets and preset to inject mock plugins; publish ./preset export and add @vitest/mocker dependency.
Builders — Webpack5
code/builders/builder-webpack5/src/presets/custom-webpack-preset.ts, .../loaders/*, .../plugins/*, package.json
Add webpackFinal to inject mock loaders/runtime, introduce loaders/plugins, switch imports to storybook/internal/mocking-utils, and export loaders in package.json with @vitest/mocker.
Addon Vitest & postinstall
code/core/src/cli/AddonVitestService.ts, code/addons/vitest/src/*, code/core/src/server-errors.ts
Add AddonVitestService (collectDependencies, validateCompatibility, installPlaywright, validateConfigFiles), remove ad-hoc postinstall logger module, add StorybookError subclasses, and refactor postinstall flows to use the service; adjust many tests.
Addon registration & postinstall helper
code/lib/cli-storybook/src/add.ts, code/lib/cli-storybook/src/postinstallAddon.ts, code/core/src/common/utils/setup-addon-in-config.ts
Delegate CSF addon registration to setupAddonInConfig; add postinstallAddon helper and getVersionSpecifier; extend PostinstallOptions with logger/prompt/skipDependencyManagement.
Core types & public API
code/core/src/types/modules/*, code/core/src/cli/projectTypes.ts, code/core/package.json, code/core/src/common/index.ts, code/core/src/manager/globals/exports.ts
Replace many union types with enums: SupportedFramework, SupportedRenderer, SupportedBuilder, SupportedLanguage, Feature, ProjectType, CoreWebpackCompiler; add/adjust exports including internal/mocking-utils.
CLI detect & tests cleanup
code/core/src/cli/detect.ts, code/core/src/cli/detect.test.ts
Remove legacy detection helpers and tests; simplify detect exports and reduce detection surface.
Logging & UX housekeeping
multiple files across core, frameworks, lib, tests
Remove "=>" prefixes, migrate console/boxen/table into logger.logBox, standardize prompt usage to node-logger.prompt, replace many console/log calls with logger.step/intro/outro; update tests accordingly.
Misc — package.json & devDeps
multiple package.json files
Remove unused devDeps (boxen, execa, prompts, ora, giget) across packages; adjust package exports and add @vitest/mocker to builders that need it.

Sequence Diagram(s)

%% Primary init/create-storybook flow (high level)
sequenceDiagram
  autonumber
  actor User
  participant CLI as "create-storybook CLI"
  participant Pre as "PreflightCheck"
  participant Detect as "ProjectDetection"
  participant Frm as "FrameworkDetection"
  participant Pref as "UserPreferences"
  participant Gen as "GeneratorExecution"
  participant Dep as "DependencyInstallation"
  participant Add as "AddonConfiguration"
  participant Fin as "Finalization"

  User->>CLI: initiate(options)
  CLI->>Pre: execute(options)
  Pre-->>CLI: { packageManager, isEmptyProject }
  CLI->>Detect: execute(...)
  Detect-->>CLI: { projectType, language }
  CLI->>Frm: execute(...)
  Frm-->>CLI: { renderer, builder, framework }
  CLI->>Pref: execute(...)
  Pref-->>CLI: { selectedFeatures }
  CLI->>Gen: execute(...)
  Gen-->>CLI: { configDir?, storybookCommand?, extraAddons }
  CLI->>Dep: execute(...)
  Dep-->>CLI: { status }
  CLI->>Add: execute(...)
  Add-->>CLI: { status }
  CLI->>Fin: execute(...)
  Fin-->>CLI: done
Loading
%% Addon Vitest interactions (high level)
sequenceDiagram
  autonumber
  participant Caller
  participant AddV as "AddonVitestService"
  participant PM as "JsPackageManager"

  Caller->>AddV: validateCompatibility(opts)
  AddV-->>Caller: { compatible, reasons? }
  Caller->>AddV: collectDependencies(PM)
  AddV-->>Caller: [packages]
  Caller->>AddV: validateConfigFiles(directory)
  AddV-->>Caller: { compatible, reasons? }
  Caller->>AddV: installPlaywright(PM, { yes? })
  AddV-->>Caller: errors[]
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~150 minutes

  • Files/areas to focus review on:
    • mocking-utils consolidation and API changes: code/core/src/mocking-utils/* and builders/loaders now importing storybook/internal/mocking-utils.
    • JsPackageManager family and proxies: code/core/src/common/js-package-manager/* (new runPackageCommand shape, PackageManagerName enum, package.json caching, executeCommand integration).
    • create-storybook rearchitecture: code/lib/create-storybook/src/initiate.ts, the new commands/*, DependencyCollector, and generator conversions.
    • node-logger redesign: code/core/src/node-logger/* (logTracker.writeToFile behavior, prompt provider changes, BoxOptions/logBox, taskLog.group).
    • Addon Vitest service & postinstall flow: code/core/src/cli/AddonVitestService.ts, code/addons/vitest/src/*, and new StorybookError subclasses.
    • Builder integrations and preset/plugin injection: Vite/Webpack presets/plugins and code/core/src/core-server/load.ts wiring.

Possibly related issues

  • [Tracking]: Modernize init flow #32643 — Modernize init flow: this PR implements the modular init/command architecture, generator-module API, and node-logger/prompt migration referenced by the issue.

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Oct 13, 2025

View your CI Pipeline Execution ↗ for commit b01def1

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 45s View ↗

☁️ Nx Cloud last updated this comment at 2025-11-19 12:57:28 UTC

@storybook-app-bot
Copy link

storybook-app-bot bot commented Oct 17, 2025

Package Benchmarks

Commit: b01def1, ran on 19 November 2025 at 12:48:58 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-a11y

Before After Difference
Dependency count 2 2 0
Self size 414 KB 181 KB 🎉 -232 KB 🎉
Dependency size 2.97 MB 2.97 MB 0 B
Bundle Size Analyzer Link Link

@storybook/addon-vitest

Before After Difference
Dependency count 6 2 🎉 -4 🎉
Self size 441 KB 375 KB 🎉 -66 KB 🎉
Dependency size 570 KB 338 KB 🎉 -232 KB 🎉
Bundle Size Analyzer Link Link

@storybook/builder-vite

Before After Difference
Dependency count 11 17 🚨 +6 🚨
Self size 291 KB 304 KB 🚨 +13 KB 🚨
Dependency size 1.30 MB 2.00 MB 🚨 +701 KB 🚨
Bundle Size Analyzer Link Link

@storybook/builder-webpack5

Before After Difference
Dependency count 187 191 🚨 +4 🚨
Self size 66 KB 75 KB 🚨 +9 KB 🚨
Dependency size 31.98 MB 32.19 MB 🚨 +215 KB 🚨
Bundle Size Analyzer Link Link

storybook

Before After Difference
Dependency count 44 39 🎉 -5 🎉
Self size 21.70 MB 19.20 MB 🎉 -2.50 MB 🎉
Dependency size 17.16 MB 16.40 MB 🎉 -755 KB 🎉
Bundle Size Analyzer Link Link

@storybook/angular

Before After Difference
Dependency count 187 191 🚨 +4 🚨
Self size 114 KB 118 KB 🚨 +3 KB 🚨
Dependency size 29.99 MB 30.22 MB 🚨 +224 KB 🚨
Bundle Size Analyzer Link Link

@storybook/ember

Before After Difference
Dependency count 191 195 🚨 +4 🚨
Self size 15 KB 15 KB 0 B
Dependency size 28.69 MB 28.91 MB 🚨 +224 KB 🚨
Bundle Size Analyzer Link Link

@storybook/html-vite

Before After Difference
Dependency count 14 20 🚨 +6 🚨
Self size 22 KB 22 KB 🚨 +12 B 🚨
Dependency size 1.63 MB 2.34 MB 🚨 +715 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 533 537 🚨 +4 🚨
Self size 645 KB 645 KB 🎉 -5 B 🎉
Dependency size 58.91 MB 59.13 MB 🚨 +224 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs-vite

Before After Difference
Dependency count 124 128 🚨 +4 🚨
Self size 1.12 MB 1.12 MB 🚨 +85 B 🚨
Dependency size 21.72 MB 21.95 MB 🚨 +229 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preact-vite

Before After Difference
Dependency count 14 20 🚨 +6 🚨
Self size 13 KB 13 KB 🚨 +12 B 🚨
Dependency size 1.61 MB 2.33 MB 🚨 +715 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-native-web-vite

Before After Difference
Dependency count 156 160 🚨 +4 🚨
Self size 30 KB 30 KB 0 B
Dependency size 22.90 MB 23.13 MB 🚨 +229 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-vite

Before After Difference
Dependency count 114 118 🚨 +4 🚨
Self size 35 KB 35 KB 🚨 +112 B 🚨
Dependency size 19.52 MB 19.75 MB 🚨 +229 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 273 277 🚨 +4 🚨
Self size 24 KB 24 KB 🚨 +12 B 🚨
Dependency size 43.85 MB 44.08 MB 🚨 +224 KB 🚨
Bundle Size Analyzer Link Link

@storybook/server-webpack5

Before After Difference
Dependency count 199 203 🚨 +4 🚨
Self size 16 KB 16 KB 0 B
Dependency size 33.23 MB 33.45 MB 🚨 +224 KB 🚨
Bundle Size Analyzer Link Link

@storybook/svelte-vite

Before After Difference
Dependency count 19 24 🚨 +5 🚨
Self size 56 KB 56 KB 0 B
Dependency size 26.75 MB 27.00 MB 🚨 +255 KB 🚨
Bundle Size Analyzer Link Link

@storybook/sveltekit

Before After Difference
Dependency count 20 25 🚨 +5 🚨
Self size 56 KB 56 KB 🎉 -24 B 🎉
Dependency size 26.80 MB 27.06 MB 🚨 +255 KB 🚨
Bundle Size Analyzer Link Link

@storybook/vue3-vite

Before After Difference
Dependency count 109 114 🚨 +5 🚨
Self size 35 KB 35 KB 🎉 -24 B 🎉
Dependency size 43.90 MB 44.15 MB 🚨 +255 KB 🚨
Bundle Size Analyzer Link Link

@storybook/web-components-vite

Before After Difference
Dependency count 15 21 🚨 +6 🚨
Self size 19 KB 19 KB 🎉 -12 B 🎉
Dependency size 1.65 MB 2.37 MB 🚨 +715 KB 🚨
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 188 173 🎉 -15 🎉
Self size 840 KB 770 KB 🎉 -70 KB 🎉
Dependency size 71.37 MB 66.17 MB 🎉 -5.21 MB 🎉
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 170 166 🎉 -4 🎉
Self size 30 KB 30 KB 🎉 -25 B 🎉
Dependency size 67.91 MB 64.74 MB 🎉 -3.17 MB 🎉
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 45 40 🎉 -5 🎉
Self size 1.45 MB 998 KB 🎉 -454 KB 🎉
Dependency size 38.86 MB 35.60 MB 🎉 -3.25 MB 🎉
Bundle Size Analyzer node node

@valentinpalkovic valentinpalkovic added ci:daily Run the CI jobs that normally run in the daily job. and removed ci:normal labels Oct 20, 2025
@valentinpalkovic valentinpalkovic self-assigned this Oct 20, 2025
@valentinpalkovic valentinpalkovic added ci:normal and removed ci:daily Run the CI jobs that normally run in the daily job. labels Oct 22, 2025
…clean up type definitions

- Changed framework property in FrameworkDetectionResult to be required instead of optional.
- Updated getFramework method to throw an error if a framework cannot be found, improving error handling.
- Removed unused type definition for Builder in project_types.ts to streamline code.
…work handling and type definitions

- Updated generatorOptions to include framework and renderer properties for better configuration.
- Simplified the getFrameworkDetails function to improve clarity and error handling.
- Removed unused builder details logic to streamline the baseGenerator function.
- Adjusted types in GeneratorOptions to reflect the new structure.
- Removed the externalFrameworks function to simplify framework detection logic.
- Updated getFrameworkDetails to enhance clarity by directly applying the require wrapper on the framework package.
- Improved overall readability and maintainability of the baseGenerator code.
- Added a prompt to ask users if they want to use Compodoc for documentation in Angular projects.
- Improved user experience by providing information about the benefits of Compodoc.
- Updated the logic to determine Compodoc usage based on user input instead of a fixed feature flag.
… addon configuration

- Updated the `doInitiate` function to pass `projectType` to user preferences and generator execution.
- Simplified the `executeGeneratorExecution` function to accept a single options object.
- Enhanced the `UserPreferencesCommand` to determine selected features based on project type.
- Adjusted addon configuration logic to utilize `extraAddons` from generator execution results.
- Improved overall code readability and maintainability by streamlining function signatures and logic.
…turn structure

- Updated the `GeneratorExecutionResult` type to improve clarity and structure by formatting the return type.
- Adjusted the return statement in `executeProjectGenerator` to conditionally include `configDir` based on the generator result.
- Improved overall readability and maintainability of the `GeneratorExecutionCommand` class.
- Updated the logging in `useStatics` to display relative paths for static directories instead of absolute paths, enhancing clarity.
- Removed unused `Builder` type imports and replaced them with `SupportedBuilder` in various files to improve type consistency and maintainability.
- Replaced string literals with SupportedBuilder constants in the AddonManager test cases for improved type safety and consistency.
- Enhanced clarity in the tests by using the defined types for builder options.
…aths

- Updated the `useStatics` function to utilize `getProjectRoot` for calculating relative static directory paths, enhancing accuracy in logging.
- Changed the logger to use `CLI_COLORS` for improved visual consistency in log messages.
- Consolidated the logging message in the `promptForCompoDocs` function to a single line for better clarity and maintainability.
- Enhanced user experience by providing a concise message about the benefits of using Compodoc for documentation in Angular projects.
- Included the `yes` option in the `GeneratorExecutionCommand` to allow automatic confirmation for prompts.
- Enhanced the command's flexibility by enabling users to bypass interactive prompts based on their preferences.
- Updated postinstall function to accept logger and prompt from options.
- Enhanced ClackPromptProvider to manage task logging more effectively.
- Streamlined logger usage in add and postinstallAddon functions.
- Removed redundant task messages in baseGenerator for cleaner output.
- Removed leading arrows from logger messages in various files to standardize output format.
- Introduced ConsoleLogger and StyledConsoleLogger classes for enhanced logging functionality.
- Added new console logger methods to improve logging capabilities and maintainability.
Comment on lines +199 to +204
optionValues: {
loglevel: debug ? 'debug' : 'info',
yes: true,
...extra,
...(template.initOptions || {}),
},
Copy link
Member

Choose a reason for hiding this comment

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

Was removal of skip-install intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it was. Otherwise, addons cannot be set up properly

};

/** Service encapsulating helpers for ProjectType usage */
export class ProjectTypeService {
Copy link
Member

Choose a reason for hiding this comment

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

This file doesn't have unit tests it seems. Did you want to add some?

Comment on lines 186 to 189
// Don't install test in CI but install in non-TTY environments like agentic installs
if (isTestFeatureAvailable) {
features.add(Feature.TEST);
}
Copy link
Member

Choose a reason for hiding this comment

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

The comment is outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (6)
code/core/src/telemetry/notify.ts (1)

20-25: Reconsider the wording "Storybook now collects".

The word "now" may mislead users into thinking telemetry is newly introduced. Based on previous review context, telemetry has been in place for some time. Consider rephrasing to avoid implying this is a new feature.

Apply this diff to clarify the message:

   logger.info(
     dedent`
-    Attention: Storybook now collects completely anonymous telemetry regarding usage. This information is used to shape Storybook's roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
+    Attention: Storybook collects completely anonymous telemetry regarding usage. This information is used to shape Storybook's roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
     https://storybook.js.org/telemetry
     `
   );
code/lib/create-storybook/src/commands/FrameworkDetectionCommand.ts (2)

12-16: Align framework nullability with downstream consumers.

As previously noted, framework is typed as nullable but downstream code in GeneratorExecutionCommand expects a non-nullable SupportedFramework. This contract mismatch should be resolved by either making framework non-nullable (and ensuring detection logic always throws on failure) or adding explicit null-handling where GeneratorOptions are constructed.


24-28: Add test coverage for FrameworkDetectionCommand.

As previously noted, this command lacks tests unlike other command modules. Please add unit tests covering builder detection logic, framework resolution branches, and error cases.

code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (2)

61-63: Honor the skipPrompt option parameter.

The skipPrompt calculation ignores options.skipPrompt, so callers that explicitly request non-interactive mode via this parameter will still see prompts (unless yes is also set). This regresses workflows that rely on the skipPrompt option.

Apply this diff to include the option parameter:

-    const skipPrompt = !isInteractive || !!this.commandOptions.yes;
+    const skipPrompt = !isInteractive || !!this.commandOptions.yes || !!options.skipPrompt;

122-125: Avoid persisting defaults when prompts are skipped.

When skipPrompt is true but skipOnboarding is undefined, this code sets settings.value.init.skipOnboarding = false, persisting a default choice that the user never made. Non-interactive runs (CI, agentic installs) should not mutate user settings.

Apply this diff to only persist explicit user choices:

-    if (skipPrompt || skipOnboarding) {
+    if (skipOnboarding !== undefined) {
       settings.value.init ||= {};
       settings.value.init.skipOnboarding = !!skipOnboarding;
     } else {
code/lib/create-storybook/src/bin/run.ts (1)

76-89: Normalize --logfile to avoid boolean true crashing writeToFile

When a user passes bare --logfile without a path, Commander sets the option value to true. That true currently flows into logTracker.writeToFile(getOptionValue('logfile')), which is likely expecting a string (or possibly undefined) and will fail once it hits fs.writeFile.

You’re already documenting that omitting [path] should fall back to debug-storybook.log, so normalizing the option before writing would make this robust:

-  .hook('postAction', async ({ getOptionValue }) => {
-    if (logTracker.shouldWriteLogsToFile) {
-      await logTracker.writeToFile(getOptionValue('logfile'));
-    }
-  });
+  .hook('postAction', async ({ getOptionValue }) => {
+    if (logTracker.shouldWriteLogsToFile) {
+      const logfileOption = getOptionValue('logfile');
+      const logfilePath =
+        typeof logfileOption === 'string' && logfileOption.trim().length > 0
+          ? logfileOption
+          : undefined; // let logTracker use its default path (debug-storybook.log)
+
+      await logTracker.writeToFile(logfilePath);
+    }
+  });

That keeps --logfile working with or without a value, and prevents accidental boolean values from blowing up the CLI.

Also applies to: 90-104, 105-109

🧹 Nitpick comments (4)
code/lib/create-storybook/src/commands/FrameworkDetectionCommand.ts (2)

44-46: Validate builder option or remove unsafe type assertion.

The type assertion options.builder as SupportedBuilder bypasses type safety. If CommandOptions.builder is already typed as SupportedBuilder | undefined, the cast is redundant. If there's a type mismatch, consider adding runtime validation to ensure the provided builder value is valid before using it.


73-75: Consider logging when framework detection returns null.

If framework can legitimately be null (per the interface contract), consider logging that scenario for debugging purposes, especially since the PR emphasizes improved logging and error handling.

code/lib/create-storybook/src/bin/run.ts (2)

28-33: Clarify and harden --features / --no-features normalization

The --features variadic option plus explicit --no-features flag is a nice API, and the options.features === false guard correctly normalizes the --no-features case to an empty array.

Two things to consider tightening here:

  1. Type safety for downstream consumers
    options.features can be:

    • Feature[] (from --features),
    • false (from --no-features, normalized to []),
    • undefined (no flag).

    To make this more robust for CommandOptions and future refactors, it would help to ensure that by the time you call initiate, options.features is always either Feature[] or undefined (never bare booleans). For example, you could explicitly coerce any non-array truthy value to undefined:

    if (options.features === false) {
      options.features = [];
    } else if (!Array.isArray(options.features)) {
      options.features = undefined;
    }
  2. Commander semantics for combined value + negated options
    Because this uses both --features <list...> and --no-features mapped to the same underlying option name, Commander’s defaulting/negation behavior can get subtle. It would be good to add a small test matrix (no flag, --features a b, --no-features) to assert the exact shapes you expect and to guard against Commander upgrades changing this behavior.

Also applies to: 118-121


81-89: Minor: simplify log-level precedence logic for readability

Functionally, the preAction hook behaves as “--loglevel overrides --debug”, which is reasonable. You currently implement this by calling setLogLevel('debug') and then calling setLogLevel(options.loglevel) if present.

For slightly clearer intent (and to avoid double-calling the setter), you could invert the condition:

const options = self.opts();

if (options.loglevel) {
  logger.setLogLevel(options.loglevel);
} else if (options.debug) {
  logger.setLogLevel('debug');
}

The behavior stays the same, but it’s easier to scan and makes the precedence explicit.

Also applies to: 90-103

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72a9017 and 7a16d82.

📒 Files selected for processing (4)
  • code/core/src/telemetry/notify.ts (2 hunks)
  • code/lib/create-storybook/src/bin/run.ts (4 hunks)
  • code/lib/create-storybook/src/commands/FrameworkDetectionCommand.ts (1 hunks)
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/lib/create-storybook/src/bin/run.ts
  • code/lib/create-storybook/src/commands/FrameworkDetectionCommand.ts
  • code/lib/create-storybook/src/commands/UserPreferencesCommand.ts
  • code/core/src/telemetry/notify.ts
🧬 Code graph analysis (3)
code/lib/create-storybook/src/bin/run.ts (2)
code/core/src/manager/settings/shortcuts.tsx (1)
  • Feature (141-141)
code/core/src/node-logger/logger/log-tracker.ts (1)
  • logTracker (97-97)
code/lib/create-storybook/src/commands/FrameworkDetectionCommand.ts (3)
code/lib/create-storybook/src/services/FrameworkDetectionService.ts (1)
  • FrameworkDetectionService (13-78)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
code/lib/create-storybook/src/generators/GeneratorRegistry.ts (1)
  • generatorRegistry (34-34)
code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (3)
code/lib/create-storybook/src/services/TelemetryService.ts (1)
  • TelemetryService (10-105)
code/lib/create-storybook/src/generators/types.ts (1)
  • CommandOptions (118-137)
code/lib/create-storybook/src/services/FeatureCompatibilityService.ts (1)
  • FeatureCompatibilityService (22-61)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (12)
code/core/src/telemetry/notify.ts (2)

2-4: LGTM! Import modernization aligns with centralized logging.

The migration from CLI_COLORS/picocolors to logger and addition of dedent improves consistency and readability.


8-16: LGTM! Guard logic correctly prevents notification spam.

The cache check ensures users are only notified once about telemetry, which is the intended behavior.

code/lib/create-storybook/src/commands/FrameworkDetectionCommand.ts (2)

1-10: LGTM: Imports are clean and appropriate.

All imports are used and properly scoped.


85-91: LGTM: Clean public API.

The helper function provides a clean, functional interface to the command while maintaining testability of the class.

code/lib/create-storybook/src/commands/UserPreferencesCommand.ts (7)

16-33: LGTM!

Type definitions are clean and well-structured. The optional skipPrompt parameter in UserPreferencesOptions provides the flexibility needed for non-interactive flows.


46-54: LGTM!

Constructor properly initializes services with appropriate dependency injection. The default FeatureCompatibilityService instance provides good testability while allowing injection.


99-114: LGTM!

The method correctly handles all three states of the features array: undefined, empty, and populated. The optional chaining and explicit length checks make the intent clear.


157-187: LGTM!

The method correctly handles both interactive and non-interactive modes, defaulting to 'recommended' when prompts are skipped. Telemetry tracking happens in both paths, which ensures visibility into installation patterns.


189-211: LGTM!

Feature determination logic is clean and correctly implements the tiered approach. The A11Y addon inclusion for recommended installs aligns with the PR objectives and improves accessibility support by default.


213-227: LGTM!

Clean delegation to the feature compatibility service. Using process.cwd() is appropriate since the command runs in the project root context.


230-235: LGTM!

The helper function provides a clean functional API for command execution while maintaining proper separation of concerns between CommandOptions and UserPreferencesOptions.

code/lib/create-storybook/src/bin/run.ts (1)

38-64: Typed .choices for package manager/parser/type/builder look solid

The use of Commander .addOption(...).choices(...) for --package-manager, --parser, --type, and --builder gives you strict, discoverable CLIs and lines up with the internal enums (PackageManagerName, ProjectType, SupportedBuilder). The filtering out of UNDETECTED, UNSUPPORTED, and NX from ProjectType avoids exposing invalid/unsupported project types on the CLI.

No issues here from my side.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
code/lib/create-storybook/src/generators/baseGenerator.ts (1)

165-172: Feature selections are still being ignored by AddonService.

The AddonService.configureAddons() method receives the features parameter but never calls getAddonsForFeatures(features) to retrieve the corresponding addon packages. This means user selections for Feature.TEST, Feature.A11Y, Feature.DOCS, etc., are silently dropped—those addons won't appear in main.js or package.json.

The fix belongs in AddonService.configureAddons: merge the results of this.getAddonsForFeatures(features) into both addonsForMain and addonPackages before returning.

🧹 Nitpick comments (2)
code/lib/create-storybook/src/generators/baseGenerator.ts (2)

199-220: Consider whether eslintPluginPackage variable is needed.

The eslintPluginPackage variable is assigned at line 207 and used once at line 208, but the actual string 'eslint-plugin-storybook' could be directly added to packagesToInstall. Unless this variable serves a future purpose (logging, debugging, etc.), it adds no value.

Apply this diff if you want to simplify:

-  let eslintPluginPackage: string | null = null;
   try {
     if (!isCI()) {
       const { hasEslint, isStorybookPluginInstalled, isFlatConfig, eslintConfigFile } =
         // TODO: Investigate why packageManager type does not match on CI
         await extractEslintInfo(packageManager as any);

       if (hasEslint && !isStorybookPluginInstalled) {
-        eslintPluginPackage = 'eslint-plugin-storybook';
-        packagesToInstall.push(eslintPluginPackage);
+        packagesToInstall.push('eslint-plugin-storybook');
         taskLog.message(`- Configuring ESLint plugin`);

226-233: Clarify the dependency collection comment.

The comment "When using the dependency collector, just collect the packages" implies the collector is optional, but dependencyCollector is a required parameter in GeneratorOptions and is always used in this refactored flow.

Consider rephrasing to:

-  // When using the dependency collector, just collect the packages
+  // Collect packages for installation; the collector will install them in a single batch later
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a16d82 and d9ca7b4.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • code/lib/create-storybook/src/generators/baseGenerator.ts (7 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/lib/create-storybook/src/generators/baseGenerator.ts
📚 Learning: 2025-09-17T07:31:04.432Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32484
File: code/core/package.json:326-326
Timestamp: 2025-09-17T07:31:04.432Z
Learning: In Storybook's core package, dependencies like `open` are bundled into the final distribution during the build process, so they should remain in devDependencies rather than being moved to dependencies. End users don't need these packages as separate runtime dependencies since they're included in the bundled code.

Applied to files:

  • code/lib/create-storybook/src/generators/baseGenerator.ts
📚 Learning: 2025-09-29T13:20:23.346Z
Learnt from: mrginglymus
Repo: storybookjs/storybook PR: 32556
File: code/core/package.json:309-313
Timestamp: 2025-09-29T13:20:23.346Z
Learning: The `fast-printf` dependency in Storybook's core package is bundled into the final distribution during the build process, so it should remain in devDependencies rather than being moved to dependencies, following the same pattern as other bundled dependencies like `open`.

Applied to files:

  • code/lib/create-storybook/src/generators/baseGenerator.ts
🧬 Code graph analysis (1)
code/lib/create-storybook/src/generators/baseGenerator.ts (6)
code/lib/create-storybook/src/generators/types.ts (2)
  • FrameworkOptions (31-47)
  • GeneratorOptions (16-29)
code/core/src/common/utils/get-storybook-info.ts (1)
  • frameworkPackages (38-61)
code/core/src/node-logger/prompts/prompt-functions.ts (1)
  • taskLog (161-230)
code/core/src/node-logger/prompts/prompt-provider-clack.ts (1)
  • taskLog (111-159)
code/lib/create-storybook/src/services/AddonService.ts (1)
  • AddonService (11-77)
code/lib/create-storybook/src/generators/configure.ts (2)
  • configureMain (46-107)
  • configurePreview (109-155)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (7)
code/lib/create-storybook/src/generators/baseGenerator.ts (7)

18-19: LGTM: Import updates support the new architecture.

The new imports (prompt for taskLog, AddonService for addon configuration) align with the modular command-based pipeline and centralized logging approach described in the PR objectives.

Also applies to: 24-24


28-40: LGTM: Good use of TypeScript's satisfies operator.

Using satisfies FrameworkOptions provides type safety while preserving the specific literal types of the default values.


42-61: LGTM: Helper function correctly maps enum values to package names.

The getPackageByValue function properly searches the package registry and provides a clear error message when a package cannot be found.


75-95: LGTM: Object parameter pattern improves API clarity.

The refactored getFrameworkDetails function uses object parameters (more maintainable) and correctly delegates framework package resolution to getPackageByValue.


108-125: LGTM: Enum-based framework list improves type safety.

The use of SupportedFramework enum values instead of strings prevents typos and ensures only valid framework identifiers are checked.


260-285: LGTM: Configuration generation with proper progress logging.

Both configureMain and configurePreview are called with the correct parameters, and taskLog.message provides clear progress updates to the user.


287-320: LGTM: Script addition, component copying, and return value are correct.

The function properly:

  • Logs each step using taskLog
  • Falls back from framework to renderer templates when needed
  • Uses invariant to fail fast if neither template source is available
  • Returns the enhanced configuration object (configDir, storybookCommand, shouldRunDev) as specified in the updated API

@valentinpalkovic valentinpalkovic merged commit eec3438 into next Nov 19, 2025
111 of 112 checks passed
@valentinpalkovic valentinpalkovic deleted the valentin/cli-init-rework branch November 19, 2025 13:03
@valentinpalkovic valentinpalkovic added the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Nov 21, 2025
@yannbf yannbf removed the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:daily Run the CI jobs that normally run in the daily job. cli feature request

Projects

None yet

5 participants