From a93ac51ae22d8c9b0e2c752f8c5228fc73be5ec3 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 13 Nov 2025 13:14:55 +0100 Subject: [PATCH 01/17] Add RSBuild-based sandboxes --- code/core/src/csf-tools/ConfigFile.ts | 2 +- .../cli-storybook/src/sandbox-templates.ts | 69 ++++++++++++++++++- scripts/tasks/sandbox-parts.ts | 2 +- scripts/tasks/sandbox.ts | 2 +- scripts/utils/yarn.ts | 6 +- 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/code/core/src/csf-tools/ConfigFile.ts b/code/core/src/csf-tools/ConfigFile.ts index 91e2e3d5c402..c5f376f5096f 100644 --- a/code/core/src/csf-tools/ConfigFile.ts +++ b/code/core/src/csf-tools/ConfigFile.ts @@ -1179,7 +1179,7 @@ export const isCsfFactoryPreview = (previewConfig: ConfigFile) => { return !!program.body.find((node) => { return ( t.isImportDeclaration(node) && - node.source.value.includes('@storybook') && + node.source.value.includes('storybook') && node.specifiers.some((specifier) => { return ( t.isImportSpecifier(specifier) && diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index 0e1140d09008..d0d6ccdbe032 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -80,6 +80,7 @@ export type Template = { */ modifications?: { skipTemplateStories?: boolean; + skipMocking?: boolean; mainConfig?: LoosenedStorybookConfig | ((config: ConfigFile) => LoosenedStorybookConfig); testBuild?: boolean; disableDocs?: boolean; @@ -101,7 +102,7 @@ export type Template = { }; type BaseTemplates = Template & { - name: `${string} ${`v${number}` | 'Latest' | 'Prerelease'} (${'Webpack' | 'Vite'} | ${ + name: `${string} ${`v${number}` | 'Latest' | 'Prerelease'} (${'Webpack' | 'Vite' | 'RSBuild'} | ${ | 'JavaScript' | 'TypeScript'})`; }; @@ -477,6 +478,22 @@ export const baseTemplates = { }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], }, + 'react-rsbuild/default-ts': { + name: 'React Latest (RSBuild | TypeScript)', + inDevelopment: true, + script: 'yarn create rsbuild -d {{beforeDir}} -t react-ts --tools eslint', + expected: { + framework: 'storybook-react-rsbuild', + renderer: '@storybook/react', + builder: 'storybook-builder-rsbuild', + }, + modifications: { + useCsfFactory: true, + extraDependencies: ['prop-types'], + skipMocking: true, + }, + skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + }, 'solid-vite/default-js': { name: 'SolidJS Latest (Vite | JavaScript)', script: 'npx degit solidjs/templates/js {{beforeDir}}', @@ -517,6 +534,21 @@ export const baseTemplates = { }, skipTasks: ['bench'], }, + 'vue3-rsbuild/default-ts': { + name: 'Vue Latest (RSBuild | TypeScript)', + inDevelopment: true, + script: 'yarn create rsbuild -d {{beforeDir}} -t vue-ts --tools eslint', + expected: { + framework: 'storybook-vue3-rsbuild', + renderer: '@storybook/vue3', + builder: 'storybook-builder-rsbuild', + }, + modifications: { + useCsfFactory: true, + skipMocking: true, + }, + skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + }, // 'nuxt-vite/default-ts': { // name: 'Nuxt v3 (Vite | TypeScript)', // script: 'npx nuxi init --packageManager yarn --gitInit false -M @nuxt/ui {{beforeDir}}', @@ -549,6 +581,21 @@ export const baseTemplates = { }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], }, + 'html-rsbuild/default-ts': { + name: 'HTML Latest (RSBuild | TypeScript)', + inDevelopment: true, + script: 'yarn create rsbuild -d {{beforeDir}} -t vanilla-ts --tools eslint', + expected: { + framework: 'storybook-html-rsbuild', + renderer: '@storybook/html', + builder: 'storybook-builder-rsbuild', + }, + modifications: { + useCsfFactory: true, + skipMocking: true, + }, + skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + }, 'svelte-vite/default-js': { name: 'Svelte Latest (Vite | JavaScript)', script: 'npm create vite --yes {{beforeDir}} -- --template svelte', @@ -627,6 +674,21 @@ export const baseTemplates = { // Remove smoke-test from the list once https://github.com/storybookjs/storybook/issues/19351 is fixed. skipTasks: ['smoke-test', 'e2e-tests', 'bench', 'vitest-integration'], }, + 'lit-rsbuild/default-ts': { + name: 'Web Components Latest (RSBuild | TypeScript)', + inDevelopment: true, + script: 'yarn create rsbuild -d {{beforeDir}} -t lit-ts --tools eslint', + expected: { + framework: 'storybook-web-components-rsbuild', + renderer: '@storybook/web-components', + builder: 'storybook-builder-rsbuild', + }, + modifications: { + useCsfFactory: true, + skipMocking: true, + }, + skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + }, 'preact-vite/default-js': { name: 'Preact Latest (Vite | JavaScript)', script: 'npm create vite --yes {{beforeDir}} -- --template preact', @@ -805,6 +867,7 @@ const benchTemplates = { isInternal: true, modifications: { skipTemplateStories: true, + skipMocking: true, }, skipTasks: [ 'e2e-tests', @@ -822,6 +885,7 @@ const benchTemplates = { isInternal: true, modifications: { skipTemplateStories: true, + skipMocking: true, }, skipTasks: [ 'e2e-tests', @@ -839,6 +903,7 @@ const benchTemplates = { modifications: { skipTemplateStories: true, disableDocs: true, + skipMocking: true, }, skipTasks: [ 'e2e-tests', @@ -857,6 +922,7 @@ const benchTemplates = { modifications: { skipTemplateStories: true, testBuild: true, + skipMocking: true, }, skipTasks: [ 'e2e-tests', @@ -874,6 +940,7 @@ const benchTemplates = { modifications: { skipTemplateStories: true, testBuild: true, + skipMocking: true, }, skipTasks: [ 'e2e-tests', diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index b02777c87e54..0a07cf99cbc0 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -833,7 +833,7 @@ export const extendPreview: Task['run'] = async ({ template, sandboxDir }) => { previewConfig.setFieldValue(['tags'], ['vitest']); } - if (template.name.includes('Bench')) { + if (template.modifications?.skipMocking) { await writeConfig(previewConfig); return; } diff --git a/scripts/tasks/sandbox.ts b/scripts/tasks/sandbox.ts index 55d4dc08b9e9..7206615d0ac4 100644 --- a/scripts/tasks/sandbox.ts +++ b/scripts/tasks/sandbox.ts @@ -142,7 +142,7 @@ export const sandbox: Task = { } // not if sandbox is bench - if (!details.template.name.includes('Bench')) { + if (!details.template.modifications?.skipMocking) { await addGlobalMocks(details, options); } diff --git a/scripts/utils/yarn.ts b/scripts/utils/yarn.ts index a69237c40d21..2427a261a095 100644 --- a/scripts/utils/yarn.ts +++ b/scripts/utils/yarn.ts @@ -143,7 +143,11 @@ export const configureYarn2ForVerdaccio = async ({ // React prereleases will have INCOMPATIBLE_PEER_DEPENDENCY errors because of transitive dependencies not allowing v19 betas key.includes('nextjs') || key.includes('react-vite/prerelease') || - key.includes('react-webpack/prerelease') + key.includes('react-webpack/prerelease') || + key.includes('react-rsbuild/default-ts') || + key.includes('vue-rsbuild/default-ts') || + key.includes('html-rsbuild/default-ts') || + key.includes('web-components-rsbuild/default-ts') ) { // Don't error with INCOMPATIBLE_PEER_DEPENDENCY for SvelteKit sandboxes, it is expected to happen with @sveltejs/vite-plugin-svelte command.push( From ca8270b72dd319562b9d61e053d6a001885f5e59 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 13 Nov 2025 13:33:04 +0100 Subject: [PATCH 02/17] undo this commit soon --- .github/workflows/generate-sandboxes.yml | 112 +++++++++++------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index 3e86e63c2547..b35bb0fb5fe1 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -6,9 +6,9 @@ on: workflow_dispatch: # To test fixes on push rather than wait for the scheduling, do the following: # 1. Uncomment the lines below and add your branch. - # push: - # branches: - # - + push: + branches: + - valentin/add-rsbuild-sandboxes # 2. Change the "ref" value to in the actions/checkout step below. # 3. Comment out the whole "generate-main" job starting at line 77 # 4. 👉 DON'T FORGET TO UNDO THE STEPS BEFORE YOU MERGE YOUR CHANGES! @@ -29,7 +29,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: next + ref: valentin/add-rsbuild-sandboxes - uses: actions/setup-node@v4 with: @@ -75,55 +75,55 @@ jobs: The generation of some or all sandboxes on the **next** branch has failed. [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) - generate-main: - name: Generate to main - if: github.repository_owner == 'storybookjs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: main - - - uses: actions/setup-node@v4 - with: - node-version-file: ".nvmrc" - - - name: Setup git user - run: | - git config --global user.name "storybook-bot" - git config --global user.email "32066757+storybook-bot@users.noreply.github.com" - - - name: Install dependencies - working-directory: ./scripts - run: node --experimental-modules ./check-dependencies.js - - - name: Compile Storybook libraries - run: yarn task --task compile --start-from=auto --no-link - - - name: Publish to local registry - run: yarn local-registry --publish - - - name: Run local registry - run: yarn local-registry --open & - - - name: Wait for registry - run: yarn wait-on tcp:127.0.0.1:6001 - - - name: Generate - id: generate - run: yarn generate-sandboxes --local-registry - - - name: Publish - # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully - if: ${{ !cancelled() }} - run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=main - - - name: Report failure to Discord - if: failure() - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} - uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554 - with: - args: | - The generation of some or all sandboxes on the **main** branch has failed. - [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) + # generate-main: + # name: Generate to main + # if: github.repository_owner == 'storybookjs' + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # with: + # ref: main + + # - uses: actions/setup-node@v4 + # with: + # node-version-file: ".nvmrc" + + # - name: Setup git user + # run: | + # git config --global user.name "storybook-bot" + # git config --global user.email "32066757+storybook-bot@users.noreply.github.com" + + # - name: Install dependencies + # working-directory: ./scripts + # run: node --experimental-modules ./check-dependencies.js + + # - name: Compile Storybook libraries + # run: yarn task --task compile --start-from=auto --no-link + + # - name: Publish to local registry + # run: yarn local-registry --publish + + # - name: Run local registry + # run: yarn local-registry --open & + + # - name: Wait for registry + # run: yarn wait-on tcp:127.0.0.1:6001 + + # - name: Generate + # id: generate + # run: yarn generate-sandboxes --local-registry + + # - name: Publish + # # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully + # if: ${{ !cancelled() }} + # run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=main + + # - name: Report failure to Discord + # if: failure() + # env: + # DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} + # uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554 + # with: + # args: | + # The generation of some or all sandboxes on the **main** branch has failed. + # [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) From 62009baf99dee887cdb318cd471418a791be0c9c Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 13 Nov 2025 15:47:05 +0100 Subject: [PATCH 03/17] Revert "undo this commit soon" This reverts commit ca8270b72dd319562b9d61e053d6a001885f5e59. --- .github/workflows/generate-sandboxes.yml | 112 +++++++++++------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index b35bb0fb5fe1..3e86e63c2547 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -6,9 +6,9 @@ on: workflow_dispatch: # To test fixes on push rather than wait for the scheduling, do the following: # 1. Uncomment the lines below and add your branch. - push: - branches: - - valentin/add-rsbuild-sandboxes + # push: + # branches: + # - # 2. Change the "ref" value to in the actions/checkout step below. # 3. Comment out the whole "generate-main" job starting at line 77 # 4. 👉 DON'T FORGET TO UNDO THE STEPS BEFORE YOU MERGE YOUR CHANGES! @@ -29,7 +29,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: valentin/add-rsbuild-sandboxes + ref: next - uses: actions/setup-node@v4 with: @@ -75,55 +75,55 @@ jobs: The generation of some or all sandboxes on the **next** branch has failed. [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) - # generate-main: - # name: Generate to main - # if: github.repository_owner == 'storybookjs' - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # with: - # ref: main - - # - uses: actions/setup-node@v4 - # with: - # node-version-file: ".nvmrc" - - # - name: Setup git user - # run: | - # git config --global user.name "storybook-bot" - # git config --global user.email "32066757+storybook-bot@users.noreply.github.com" - - # - name: Install dependencies - # working-directory: ./scripts - # run: node --experimental-modules ./check-dependencies.js - - # - name: Compile Storybook libraries - # run: yarn task --task compile --start-from=auto --no-link - - # - name: Publish to local registry - # run: yarn local-registry --publish - - # - name: Run local registry - # run: yarn local-registry --open & - - # - name: Wait for registry - # run: yarn wait-on tcp:127.0.0.1:6001 - - # - name: Generate - # id: generate - # run: yarn generate-sandboxes --local-registry - - # - name: Publish - # # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully - # if: ${{ !cancelled() }} - # run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=main - - # - name: Report failure to Discord - # if: failure() - # env: - # DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} - # uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554 - # with: - # args: | - # The generation of some or all sandboxes on the **main** branch has failed. - # [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) + generate-main: + name: Generate to main + if: github.repository_owner == 'storybookjs' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + + - name: Setup git user + run: | + git config --global user.name "storybook-bot" + git config --global user.email "32066757+storybook-bot@users.noreply.github.com" + + - name: Install dependencies + working-directory: ./scripts + run: node --experimental-modules ./check-dependencies.js + + - name: Compile Storybook libraries + run: yarn task --task compile --start-from=auto --no-link + + - name: Publish to local registry + run: yarn local-registry --publish + + - name: Run local registry + run: yarn local-registry --open & + + - name: Wait for registry + run: yarn wait-on tcp:127.0.0.1:6001 + + - name: Generate + id: generate + run: yarn generate-sandboxes --local-registry + + - name: Publish + # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully + if: ${{ !cancelled() }} + run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=main + + - name: Report failure to Discord + if: failure() + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} + uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554 + with: + args: | + The generation of some or all sandboxes on the **main** branch has failed. + [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) From f280b95eb28b5da7e6a857cb4373ed848ea24547 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 13 Nov 2025 15:51:46 +0100 Subject: [PATCH 04/17] Introduce rsbuild sandboxes to CI tests --- .circleci/config.yml | 28 +++++++++---------- .circleci/src/workflows/daily.yml | 8 +++--- .circleci/src/workflows/merged.yml | 8 +++--- .circleci/src/workflows/normal.yml | 8 +++--- .../cli-storybook/src/sandbox-templates.ts | 8 +++--- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 03b288e6a061..7613b1e62adf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -925,7 +925,7 @@ jobs: shell: bash.exe test-init-features: executor: - class: medium+ + class: small name: sb_node_22_browsers steps: - git-shallow-clone/checkout_advanced: @@ -950,7 +950,7 @@ jobs: mkdir features-1 cd features-1 npm set registry http://localhost:6001 - npx create-storybook --yes --package-manager npm --features dev docs test a11y + npx create-storybook --yes --package-manager npm --features docs test a11y --loglevel=debug npx vitest environment: IN_STORYBOOK_SANDBOX: true @@ -1172,7 +1172,7 @@ workflows: requires: - build - create-sandboxes: - parallelism: 34 + parallelism: 38 requires: - build - check-sandboxes: @@ -1180,7 +1180,7 @@ workflows: requires: - create-sandboxes - chromatic-sandboxes: - parallelism: 31 + parallelism: 35 requires: - create-sandboxes - e2e-production: @@ -1188,11 +1188,11 @@ workflows: requires: - create-sandboxes - e2e-dev: - parallelism: 28 + parallelism: 32 requires: - create-sandboxes - test-runner-production: - parallelism: 29 + parallelism: 33 requires: - create-sandboxes - vitest-integration: @@ -1286,11 +1286,11 @@ workflows: requires: - unit-tests - create-sandboxes: - parallelism: 19 + parallelism: 21 requires: - build - chromatic-sandboxes: - parallelism: 16 + parallelism: 18 requires: - create-sandboxes - e2e-production: @@ -1298,11 +1298,11 @@ workflows: requires: - create-sandboxes - e2e-dev: - parallelism: 14 + parallelism: 16 requires: - create-sandboxes - test-runner-production: - parallelism: 14 + parallelism: 16 requires: - create-sandboxes - vitest-integration: @@ -1381,11 +1381,11 @@ workflows: requires: - unit-tests - create-sandboxes: - parallelism: 13 + parallelism: 14 requires: - build - chromatic-sandboxes: - parallelism: 10 + parallelism: 11 requires: - create-sandboxes - e2e-production: @@ -1393,11 +1393,11 @@ workflows: requires: - create-sandboxes - e2e-dev: - parallelism: 8 + parallelism: 9 requires: - create-sandboxes - test-runner-production: - parallelism: 8 + parallelism: 9 requires: - create-sandboxes - vitest-integration: diff --git a/.circleci/src/workflows/daily.yml b/.circleci/src/workflows/daily.yml index 5af817bd33c9..7d4fbee1a568 100644 --- a/.circleci/src/workflows/daily.yml +++ b/.circleci/src/workflows/daily.yml @@ -31,7 +31,7 @@ jobs: requires: - build - create-sandboxes: - parallelism: 34 + parallelism: 38 requires: - build - check-sandboxes: @@ -42,7 +42,7 @@ jobs: # requires: # - create-sandboxes - chromatic-sandboxes: - parallelism: 31 + parallelism: 35 requires: - create-sandboxes - e2e-production: @@ -50,11 +50,11 @@ jobs: requires: - create-sandboxes - e2e-dev: - parallelism: 28 + parallelism: 32 requires: - create-sandboxes - test-runner-production: - parallelism: 29 + parallelism: 33 requires: - create-sandboxes - vitest-integration: diff --git a/.circleci/src/workflows/merged.yml b/.circleci/src/workflows/merged.yml index e0b5528a93bf..ec8cb9fd4365 100644 --- a/.circleci/src/workflows/merged.yml +++ b/.circleci/src/workflows/merged.yml @@ -34,11 +34,11 @@ jobs: requires: - unit-tests - create-sandboxes: - parallelism: 19 + parallelism: 21 requires: - build - chromatic-sandboxes: - parallelism: 16 + parallelism: 18 requires: - create-sandboxes - e2e-production: @@ -46,11 +46,11 @@ jobs: requires: - create-sandboxes - e2e-dev: - parallelism: 14 + parallelism: 16 requires: - create-sandboxes - test-runner-production: - parallelism: 14 + parallelism: 16 requires: - create-sandboxes - vitest-integration: diff --git a/.circleci/src/workflows/normal.yml b/.circleci/src/workflows/normal.yml index 1fe5bf46ed63..ad880ff61886 100644 --- a/.circleci/src/workflows/normal.yml +++ b/.circleci/src/workflows/normal.yml @@ -34,11 +34,11 @@ jobs: requires: - unit-tests - create-sandboxes: - parallelism: 13 + parallelism: 14 requires: - build - chromatic-sandboxes: - parallelism: 10 + parallelism: 11 requires: - create-sandboxes - e2e-production: @@ -46,11 +46,11 @@ jobs: requires: - create-sandboxes - e2e-dev: - parallelism: 8 + parallelism: 9 requires: - create-sandboxes - test-runner-production: - parallelism: 8 + parallelism: 9 requires: - create-sandboxes - vitest-integration: diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index d0d6ccdbe032..4d69c2b5fd8c 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -480,7 +480,6 @@ export const baseTemplates = { }, 'react-rsbuild/default-ts': { name: 'React Latest (RSBuild | TypeScript)', - inDevelopment: true, script: 'yarn create rsbuild -d {{beforeDir}} -t react-ts --tools eslint', expected: { framework: 'storybook-react-rsbuild', @@ -536,7 +535,6 @@ export const baseTemplates = { }, 'vue3-rsbuild/default-ts': { name: 'Vue Latest (RSBuild | TypeScript)', - inDevelopment: true, script: 'yarn create rsbuild -d {{beforeDir}} -t vue-ts --tools eslint', expected: { framework: 'storybook-vue3-rsbuild', @@ -583,7 +581,6 @@ export const baseTemplates = { }, 'html-rsbuild/default-ts': { name: 'HTML Latest (RSBuild | TypeScript)', - inDevelopment: true, script: 'yarn create rsbuild -d {{beforeDir}} -t vanilla-ts --tools eslint', expected: { framework: 'storybook-html-rsbuild', @@ -676,7 +673,6 @@ export const baseTemplates = { }, 'lit-rsbuild/default-ts': { name: 'Web Components Latest (RSBuild | TypeScript)', - inDevelopment: true, script: 'yarn create rsbuild -d {{beforeDir}} -t lit-ts --tools eslint', expected: { framework: 'storybook-web-components-rsbuild', @@ -976,6 +972,7 @@ export const normal: TemplateKey[] = [ 'bench/react-vite-default-ts-test-build', 'bench/react-webpack-18-ts-test-build', 'ember/default-js', + 'react-rsbuild/default-ts', ]; export const merged: TemplateKey[] = [ @@ -986,6 +983,7 @@ export const merged: TemplateKey[] = [ 'nextjs-vite/15-ts', 'preact-vite/default-ts', 'html-vite/default-ts', + 'vue3-rsbuild/default-ts', ]; export const daily: TemplateKey[] = [ @@ -1008,6 +1006,8 @@ export const daily: TemplateKey[] = [ 'internal/react16-webpack', 'internal/react18-webpack-babel', 'react-native-web-vite/expo-ts', + 'lit-rsbuild/default-ts', + 'html-rsbuild/default-ts', // 'react-native-web-vite/rn-cli-ts', ]; From ca8093d632846abecb8cab79037040e4738bbae9 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 19 Nov 2025 13:00:38 +0000 Subject: [PATCH 05/17] Add rsbuild dependencies to base templates and update resolutions for react-rsbuild --- code/lib/cli-storybook/src/sandbox-templates.ts | 5 ++++- scripts/utils/yarn.ts | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index 0582847d496a..4aab5afa00d5 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -492,7 +492,7 @@ export const baseTemplates = { }, modifications: { useCsfFactory: true, - extraDependencies: ['prop-types'], + extraDependencies: ['prop-types', 'storybook-react-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], @@ -547,6 +547,7 @@ export const baseTemplates = { }, modifications: { useCsfFactory: true, + extraDependencies: ['storybook-vue3-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], @@ -599,6 +600,7 @@ export const baseTemplates = { }, modifications: { useCsfFactory: true, + extraDependencies: ['storybook-html-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], @@ -691,6 +693,7 @@ export const baseTemplates = { }, modifications: { useCsfFactory: true, + extraDependencies: ['storybook-web-components-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], diff --git a/scripts/utils/yarn.ts b/scripts/utils/yarn.ts index 2427a261a095..0f202d105d6f 100644 --- a/scripts/utils/yarn.ts +++ b/scripts/utils/yarn.ts @@ -103,7 +103,11 @@ export const addWorkaroundResolutions = async ({ react: packageJson.dependencies.react, 'react-dom': packageJson.dependencies['react-dom'], } - : {}; + : key === 'react-rsbuild/default-ts' + ? { + 'react-docgen': '^8.0.2', + } + : {}; packageJson.resolutions = { ...packageJson.resolutions, From b5e86cd5221e0fb151a538a4ea77009ac5078a77 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 19 Nov 2025 16:39:02 +0100 Subject: [PATCH 06/17] Filter out 'docs' addon stories for specific RSBUILD frameworks in sandbox-parts task --- scripts/tasks/sandbox-parts.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index e9722471f02c..c657b37c128f 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -724,6 +724,17 @@ export const addStories: Task['run'] = async ( .filter((addon: string) => Object.keys(storybookPackages).find((pkg: string) => pkg === `@storybook/addon-${addon}`) ) + .filter((addon: string) => { + // RSBUILD frameworks are not configured to ignore docs addon stories, which are React based + if ( + template.expected.framework === 'storybook-vue3-rsbuild' || + template.expected.framework === 'storybook-web-components-rsbuild' || + template.expected.framework === 'storybook-html-rsbuild' + ) { + return addon !== 'docs'; + } + return true; + }) .map(async (addon) => workspacePath('addon', `@storybook/addon-${addon}`)) ); From 05c1652a8eafde6ca22e52bb9c4a89f3615e6691 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 19 Nov 2025 16:20:13 +0000 Subject: [PATCH 07/17] Refactor getFrameworkInfo to include configDir parameter and update framework metadata retrieval --- code/core/src/telemetry/get-framework-info.ts | 76 ++----------------- code/core/src/telemetry/storybook-metadata.ts | 2 +- 2 files changed, 8 insertions(+), 70 deletions(-) diff --git a/code/core/src/telemetry/get-framework-info.ts b/code/core/src/telemetry/get-framework-info.ts index d114501481f0..dd25f1d48931 100644 --- a/code/core/src/telemetry/get-framework-info.ts +++ b/code/core/src/telemetry/get-framework-info.ts @@ -1,80 +1,18 @@ -import { normalize } from 'node:path'; +import { getStorybookInfo } from 'storybook/internal/common'; +import type { StorybookConfig } from 'storybook/internal/types'; -import { frameworkPackages } from 'storybook/internal/common'; -import type { PackageJson, StorybookConfig } from 'storybook/internal/types'; +export async function getFrameworkInfo(mainConfig: StorybookConfig, configDir: string) { + const { frameworkPackage, rendererPackage, builderPackage } = await getStorybookInfo(configDir); -import { getActualPackageJson } from './package-json'; -import { cleanPaths } from './sanitize'; - -const knownRenderers = [ - 'html', - 'react', - 'svelte', - 'vue3', - 'preact', - 'server', - 'vue', - 'web-components', - 'angular', - 'ember', -]; - -const knownBuilders = ['builder-webpack5', 'builder-vite']; - -function findMatchingPackage(packageJson: PackageJson, suffixes: string[]) { - const { name = '', version, dependencies, devDependencies, peerDependencies } = packageJson; - - const allDependencies = { - // We include the framework itself because it may be a renderer too (e.g. angular) - [name]: version, - ...dependencies, - ...devDependencies, - ...peerDependencies, - }; - - return suffixes.map((suffix) => `@storybook/${suffix}`).find((pkg) => allDependencies[pkg]); -} - -export const getFrameworkPackageName = (packageNameOrPath: string) => { - const normalizedPath = normalize(packageNameOrPath).replace(new RegExp(/\\/, 'g'), '/'); - - const knownFramework = Object.keys(frameworkPackages).find((pkg) => normalizedPath.endsWith(pkg)); - - return knownFramework || cleanPaths(packageNameOrPath).replace(/.*node_modules[\\/]/, ''); -}; - -export async function getFrameworkInfo(mainConfig: StorybookConfig) { - if (!mainConfig?.framework) { - return {}; - } - - const rawName = - typeof mainConfig.framework === 'string' ? mainConfig.framework : mainConfig.framework?.name; - if (!rawName) { - return {}; - } - - const frameworkPackageJson = await getActualPackageJson(rawName); - - if (!frameworkPackageJson) { - return {}; - } - - const builder = findMatchingPackage(frameworkPackageJson, knownBuilders); - const renderer = findMatchingPackage(frameworkPackageJson, knownRenderers); - - // TODO: Evaluate if this is correct after removing pnp compatibility code in SB11 - // parse framework name and strip off pnp paths etc. - const sanitizedFrameworkName = getFrameworkPackageName(rawName); const frameworkOptions = typeof mainConfig.framework === 'object' ? mainConfig.framework.options : {}; return { framework: { - name: sanitizedFrameworkName, + name: frameworkPackage, options: frameworkOptions, }, - builder, - renderer, + builder: builderPackage, + renderer: rendererPackage, }; } diff --git a/code/core/src/telemetry/storybook-metadata.ts b/code/core/src/telemetry/storybook-metadata.ts index c6f5db760e31..56d4f7a357cb 100644 --- a/code/core/src/telemetry/storybook-metadata.ts +++ b/code/core/src/telemetry/storybook-metadata.ts @@ -143,7 +143,7 @@ export const computeStorybookMetadata = async ({ metadata.typescriptOptions = mainConfig.typescript; } - const frameworkInfo = await getFrameworkInfo(mainConfig); + const frameworkInfo = await getFrameworkInfo(mainConfig, configDir); if (typeof mainConfig.refs === 'object') { metadata.refCount = Object.keys(mainConfig.refs).length; From 1e02a9e8601c1ac4864d46a038ecf1a3f543067c Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 19 Nov 2025 18:29:03 +0000 Subject: [PATCH 08/17] Make framework name optional in StorybookMetadata type --- code/core/src/telemetry/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/core/src/telemetry/types.ts b/code/core/src/telemetry/types.ts index c6ea3cd99354..823837ab6d73 100644 --- a/code/core/src/telemetry/types.ts +++ b/code/core/src/telemetry/types.ts @@ -54,7 +54,7 @@ export type StorybookMetadata = { userSince?: number; language: 'typescript' | 'javascript'; framework?: { - name: string; + name?: string; options?: any; }; builder?: string; From edd2e2f1b093bc4b035642b09879f3052abef607 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 19 Nov 2025 18:48:55 +0000 Subject: [PATCH 09/17] Fix tests --- .../src/telemetry/get-framework-info.test.ts | 73 ++++++++----------- 1 file changed, 31 insertions(+), 42 deletions(-) diff --git a/code/core/src/telemetry/get-framework-info.test.ts b/code/core/src/telemetry/get-framework-info.test.ts index 8fc25c4b99ca..948e1bb43720 100644 --- a/code/core/src/telemetry/get-framework-info.test.ts +++ b/code/core/src/telemetry/get-framework-info.test.ts @@ -1,58 +1,47 @@ -import { sep } from 'node:path'; - -import { describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import type { StorybookConfig } from 'storybook/internal/types'; import { getFrameworkInfo } from './get-framework-info'; -import { getActualPackageJson } from './package-json'; -vi.mock('./package-json', () => ({ - getActualPackageJson: vi.fn(), +vi.mock('storybook/internal/common', () => ({ + getStorybookInfo: vi.fn(), })); describe('getFrameworkInfo', () => { - it('should return an empty object if mainConfig.framework is undefined', async () => { - const result = await getFrameworkInfo({} as StorybookConfig); - expect(result).toEqual({}); + const defaultInfo = { + frameworkPackage: '@storybook/react', + rendererPackage: '@storybook/react', + builderPackage: '@storybook/builder-vite', + }; + + beforeEach(async () => { + const { getStorybookInfo } = await import('storybook/internal/common'); + vi.mocked(getStorybookInfo).mockResolvedValue(defaultInfo as any); }); - it('should return an empty object if mainConfig.framework name is undefined', async () => { - const result = await getFrameworkInfo({ framework: {} } as StorybookConfig); - expect(result).toEqual({}); + it('returns framework/builder/renderer with empty options when no framework provided', async () => { + const result = await getFrameworkInfo({} as StorybookConfig, '/tmp/.storybook'); + expect(result).toEqual({ + framework: { name: defaultInfo.frameworkPackage, options: {} }, + builder: defaultInfo.builderPackage, + renderer: defaultInfo.rendererPackage, + }); }); - it('should call getActualPackageJson with the correct package name', async () => { - const packageName = '@storybook/react'; - const framework = { name: packageName }; - await getFrameworkInfo({ framework } as StorybookConfig); - expect(getActualPackageJson).toHaveBeenCalledWith(packageName); + it('passes configDir to getStorybookInfo', async () => { + const configDir = '/my/project/.storybook'; + const { getStorybookInfo } = await import('storybook/internal/common'); + await getFrameworkInfo({} as StorybookConfig, configDir); + expect(getStorybookInfo).toHaveBeenCalledWith(configDir); }); - it('should resolve the framework package json correctly and strip project paths in the metadata', async () => { - const packageName = `${process.cwd()}/@storybook/react`.split('/').join(sep); - const framework = { name: packageName }; - const frameworkPackageJson = { - name: packageName, - dependencies: { - '@storybook/react': '7.0.0', - '@storybook/builder-vite': '7.0.0', - }, - }; - - vi.mocked(getActualPackageJson).mockResolvedValueOnce(frameworkPackageJson); - - const result = await getFrameworkInfo({ framework } as StorybookConfig); - - expect(getActualPackageJson).toHaveBeenCalledWith(packageName); - - expect(result).toEqual({ - framework: { - name: '$SNIP/@storybook/react'.split('/').join(sep), - options: undefined, - }, - builder: '@storybook/builder-vite', - renderer: '@storybook/react', - }); + it('returns provided framework options when object is passed', async () => { + const options = { foo: 'bar' } as any; + const result = await getFrameworkInfo( + { framework: { name: '@storybook/react', options } } as any, + '/tmp/.storybook' + ); + expect(result.framework.options).toEqual(options); }); }); From 585d93f56997b4242902836c3df3f3975e3461ad Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 11:14:48 +0100 Subject: [PATCH 10/17] Enhance framework info retrieval by sanitizing package paths and updating tests to reflect new structure --- code/core/src/telemetry/get-framework-info.ts | 12 +- .../src/telemetry/storybook-metadata.test.ts | 109 ++++++++---------- 2 files changed, 56 insertions(+), 65 deletions(-) diff --git a/code/core/src/telemetry/get-framework-info.ts b/code/core/src/telemetry/get-framework-info.ts index dd25f1d48931..51dd5feeb78e 100644 --- a/code/core/src/telemetry/get-framework-info.ts +++ b/code/core/src/telemetry/get-framework-info.ts @@ -1,6 +1,12 @@ import { getStorybookInfo } from 'storybook/internal/common'; import type { StorybookConfig } from 'storybook/internal/types'; +import { cleanPaths } from './sanitize'; + +const cleanAndSanitizePath = (path: string) => { + return cleanPaths(path).replace(/.*node_modules[\\/]/, ''); +}; + export async function getFrameworkInfo(mainConfig: StorybookConfig, configDir: string) { const { frameworkPackage, rendererPackage, builderPackage } = await getStorybookInfo(configDir); @@ -9,10 +15,10 @@ export async function getFrameworkInfo(mainConfig: StorybookConfig, configDir: s return { framework: { - name: frameworkPackage, + name: frameworkPackage ? cleanAndSanitizePath(frameworkPackage) : undefined, options: frameworkOptions, }, - builder: builderPackage, - renderer: rendererPackage, + builder: builderPackage ? cleanAndSanitizePath(builderPackage) : undefined, + renderer: rendererPackage ? cleanAndSanitizePath(rendererPackage) : undefined, }; } diff --git a/code/core/src/telemetry/storybook-metadata.test.ts b/code/core/src/telemetry/storybook-metadata.test.ts index 6bc4fe11002f..816fc75d6a19 100644 --- a/code/core/src/telemetry/storybook-metadata.test.ts +++ b/code/core/src/telemetry/storybook-metadata.test.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import type { MockInstance } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { getStorybookInfo, isCI } from 'storybook/internal/common'; +import { getStorybookInfo, isCI, loadMainConfig } from 'storybook/internal/common'; import { type PackageJson, type StorybookConfig, @@ -14,6 +14,15 @@ import { import { detect } from 'package-manager-detector'; +import { frameworkToBuilder } from '../../common/utils/framework'; +import { getAddonNames } from '../../common/utils/get-addon-names'; +import { extractFrameworkPackageName } from '../../common/utils/get-framework-name'; +import { extractRenderer } from '../../common/utils/get-renderer-name'; +import { + builderPackages, + frameworkPackages, + rendererPackages, +} from '../../common/utils/get-storybook-info'; import { type Settings, globalSettings } from '../cli/globalSettings'; import { getMonorepoType } from '../telemetry/get-monorepo-type'; import { @@ -40,19 +49,25 @@ const mainJsMock: StorybookConfig = { stories: [], }; +const defaultInfo = { + framework: SupportedFramework.REACT_VITE, + renderer: SupportedRenderer.REACT, + builder: SupportedBuilder.VITE, + frameworkPackage: '@storybook/react-vite', + rendererPackage: '@storybook/react', + builderPackage: '@storybook/builder-vite', + addons: [], + mainConfig: { + stories: [], + }, + mainConfigPath: '', + previewConfigPath: '', + managerConfigPath: '', + version: 'x.x.x', +}; + beforeEach(() => { - vi.mocked(getStorybookInfo).mockImplementation(async () => ({ - framework: SupportedFramework.REACT_VITE, - renderer: SupportedRenderer.REACT, - builder: SupportedBuilder.VITE, - addons: [], - mainConfig: { - stories: [], - }, - mainConfigPath: '', - previewConfigPath: '', - managerConfigPath: '', - })); + vi.mocked(getStorybookInfo).mockImplementation(async () => defaultInfo); vi.mocked(detect).mockImplementation(async () => ({ name: 'yarn', @@ -84,13 +99,11 @@ const originalSep = path.sep; describe('storybook-metadata', () => { let cwdSpy: MockInstance; beforeEach(() => { - // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = originalSep; }); afterEach(() => { cwdSpy?.mockRestore(); - // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = originalSep; }); @@ -120,7 +133,6 @@ describe('storybook-metadata', () => { }); it('Windows paths', () => { - // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = '\\'; const cwdMockPath = `C:\\Users\\username\\storybook-app`; cwdSpy = vi.spyOn(process, `cwd`).mockReturnValueOnce(cwdMockPath); @@ -131,7 +143,6 @@ describe('storybook-metadata', () => { }); it('Linux paths', () => { - // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = '/'; const cwdMockPath = `/Users/username/storybook-app`; cwdSpy = vi.spyOn(process, `cwd`).mockReturnValue(cwdMockPath); @@ -187,6 +198,12 @@ describe('storybook-metadata', () => { }); it('should parse pnp paths for unknown frameworks', async () => { + vi.mocked(getStorybookInfo).mockImplementation(async () => ({ + ...defaultInfo, + frameworkPackage: + '/Users/foo/my-project/.yarn/__virtual__/@storybook-react-vite-virtual-769c990b9/0/cache/@storybook-react-rust-npm-7.1.0-alpha.38-512b-a23.zip/node_modules/storybook-react-rust' as any, + })); + const unixResult = await computeStorybookMetadata({ packageJson: packageJsonMock, packageJsonPath, @@ -221,10 +238,14 @@ describe('storybook-metadata', () => { }); it('should sanitize pnp paths for local frameworks', async () => { - // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = '/'; cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue('/Users/foo/my-projects'); + vi.mocked(getStorybookInfo).mockImplementation(async () => ({ + ...defaultInfo, + frameworkPackage: '/Users/foo/my-projects/.storybook/some-local-framework' as any, + })); + const unixResult = await computeStorybookMetadata({ packageJson: packageJsonMock, packageJsonPath, @@ -240,10 +261,17 @@ describe('storybook-metadata', () => { expect(unixResult.framework).toEqual({ name: '$SNIP/.storybook/some-local-framework', }); + }); - // @ts-expect-error the property is read only but we can change it for testing purposes + it('should sanitize pnp paths for local frameworks on Windows', async () => { path.sep = '\\'; cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue('C:\\Users\\foo\\my-project'); + + vi.mocked(getStorybookInfo).mockImplementation(async () => ({ + ...defaultInfo, + frameworkPackage: 'C:\\Users\\foo\\my-project\\.storybook\\some-local-framework' as any, + })); + const windowsResult = await computeStorybookMetadata({ packageJson: packageJsonMock, packageJsonPath, @@ -262,49 +290,6 @@ describe('storybook-metadata', () => { }); }); - it('should return frameworkOptions from mainjs', async () => { - const reactResult = await computeStorybookMetadata({ - packageJson: packageJsonMock, - packageJsonPath, - configDir: '.storybook', - mainConfig: { - ...mainJsMock, - framework: { - name: '@storybook/react-vite', - options: { - strictMode: false, - }, - }, - }, - }); - - expect(reactResult.framework).toEqual({ - name: '@storybook/react-vite', - options: { strictMode: false }, - }); - - const angularResult = await computeStorybookMetadata({ - packageJson: packageJsonMock, - packageJsonPath, - configDir: '.storybook', - mainConfig: { - ...mainJsMock, - framework: { - name: '@storybook/angular', - options: { - enableIvy: true, - enableNgcc: true, - }, - }, - }, - }); - - expect(angularResult.framework).toEqual({ - name: '@storybook/angular', - options: { enableIvy: true, enableNgcc: true }, - }); - }); - it('should separate storybook packages and addons', async () => { const result = await computeStorybookMetadata({ packageJson: { From 80bd74b99c81a42f1b1f220609675c0a755f5d40 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 11:33:49 +0100 Subject: [PATCH 11/17] Fix types --- .../src/telemetry/storybook-metadata.test.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/code/core/src/telemetry/storybook-metadata.test.ts b/code/core/src/telemetry/storybook-metadata.test.ts index 816fc75d6a19..600b2e4e60e7 100644 --- a/code/core/src/telemetry/storybook-metadata.test.ts +++ b/code/core/src/telemetry/storybook-metadata.test.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import type { MockInstance } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { getStorybookInfo, isCI, loadMainConfig } from 'storybook/internal/common'; +import { getStorybookInfo, isCI } from 'storybook/internal/common'; import { type PackageJson, type StorybookConfig, @@ -14,15 +14,6 @@ import { import { detect } from 'package-manager-detector'; -import { frameworkToBuilder } from '../../common/utils/framework'; -import { getAddonNames } from '../../common/utils/get-addon-names'; -import { extractFrameworkPackageName } from '../../common/utils/get-framework-name'; -import { extractRenderer } from '../../common/utils/get-renderer-name'; -import { - builderPackages, - frameworkPackages, - rendererPackages, -} from '../../common/utils/get-storybook-info'; import { type Settings, globalSettings } from '../cli/globalSettings'; import { getMonorepoType } from '../telemetry/get-monorepo-type'; import { @@ -99,11 +90,13 @@ const originalSep = path.sep; describe('storybook-metadata', () => { let cwdSpy: MockInstance; beforeEach(() => { + // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = originalSep; }); afterEach(() => { cwdSpy?.mockRestore(); + // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = originalSep; }); @@ -133,6 +126,7 @@ describe('storybook-metadata', () => { }); it('Windows paths', () => { + // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = '\\'; const cwdMockPath = `C:\\Users\\username\\storybook-app`; cwdSpy = vi.spyOn(process, `cwd`).mockReturnValueOnce(cwdMockPath); @@ -143,6 +137,7 @@ describe('storybook-metadata', () => { }); it('Linux paths', () => { + // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = '/'; const cwdMockPath = `/Users/username/storybook-app`; cwdSpy = vi.spyOn(process, `cwd`).mockReturnValue(cwdMockPath); @@ -238,6 +233,7 @@ describe('storybook-metadata', () => { }); it('should sanitize pnp paths for local frameworks', async () => { + // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = '/'; cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue('/Users/foo/my-projects'); @@ -264,6 +260,7 @@ describe('storybook-metadata', () => { }); it('should sanitize pnp paths for local frameworks on Windows', async () => { + // @ts-expect-error the property is read only but we can change it for testing purposes path.sep = '\\'; cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue('C:\\Users\\foo\\my-project'); From bac0e91d5d0fc302482e98f187b8f95cc39b8575 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 11:43:56 +0000 Subject: [PATCH 12/17] Don't use csf factories for rsbuild --- code/lib/cli-storybook/src/sandbox-templates.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index 12388f616a6b..b5d12c7dd5d1 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -491,7 +491,6 @@ export const baseTemplates = { builder: 'storybook-builder-rsbuild', }, modifications: { - useCsfFactory: true, extraDependencies: ['prop-types', 'storybook-react-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, @@ -546,7 +545,6 @@ export const baseTemplates = { builder: 'storybook-builder-rsbuild', }, modifications: { - useCsfFactory: true, extraDependencies: ['storybook-vue3-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, @@ -599,7 +597,6 @@ export const baseTemplates = { builder: 'storybook-builder-rsbuild', }, modifications: { - useCsfFactory: true, extraDependencies: ['storybook-html-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, @@ -699,7 +696,6 @@ export const baseTemplates = { builder: 'storybook-builder-rsbuild', }, modifications: { - useCsfFactory: true, extraDependencies: ['storybook-web-components-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, From 6713380739a6252903ed957c17ca3df59b0a60c9 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 12:52:20 +0000 Subject: [PATCH 13/17] Update template names to use 'RsBuild' and add experimental test syntax configuration --- .../cli-storybook/src/sandbox-templates.ts | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index b5d12c7dd5d1..8170a604163d 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -106,7 +106,7 @@ export type Template = { }; type BaseTemplates = Template & { - name: `${string} ${`v${number}` | 'Latest' | 'Prerelease'} (${'Webpack' | 'Vite' | 'RSBuild'} | ${ + name: `${string} ${`v${number}` | 'Latest' | 'Prerelease'} (${'Webpack' | 'Vite' | 'RsBuild'} | ${ | 'JavaScript' | 'TypeScript'})`; }; @@ -483,7 +483,7 @@ export const baseTemplates = { skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], }, 'react-rsbuild/default-ts': { - name: 'React Latest (RSBuild | TypeScript)', + name: 'React Latest (RsBuild | TypeScript)', script: 'yarn create rsbuild -d {{beforeDir}} -t react-ts --tools eslint', expected: { framework: 'storybook-react-rsbuild', @@ -492,6 +492,12 @@ export const baseTemplates = { }, modifications: { extraDependencies: ['prop-types', 'storybook-react-rsbuild@^3.0.0-beta.1'], + useCsfFactory: true, + mainConfig: { + features: { + experimentalTestSyntax: true, + }, + }, skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], @@ -537,7 +543,7 @@ export const baseTemplates = { skipTasks: ['bench'], }, 'vue3-rsbuild/default-ts': { - name: 'Vue Latest (RSBuild | TypeScript)', + name: 'Vue Latest (RsBuild | TypeScript)', script: 'yarn create rsbuild -d {{beforeDir}} -t vue-ts --tools eslint', expected: { framework: 'storybook-vue3-rsbuild', @@ -546,6 +552,12 @@ export const baseTemplates = { }, modifications: { extraDependencies: ['storybook-vue3-rsbuild@^3.0.0-beta.1'], + useCsfFactory: true, + mainConfig: { + features: { + experimentalTestSyntax: true, + }, + }, skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], @@ -589,7 +601,7 @@ export const baseTemplates = { }, }, 'html-rsbuild/default-ts': { - name: 'HTML Latest (RSBuild | TypeScript)', + name: 'HTML Latest (RsBuild | TypeScript)', script: 'yarn create rsbuild -d {{beforeDir}} -t vanilla-ts --tools eslint', expected: { framework: 'storybook-html-rsbuild', @@ -598,6 +610,12 @@ export const baseTemplates = { }, modifications: { extraDependencies: ['storybook-html-rsbuild@^3.0.0-beta.1'], + useCsfFactory: true, + mainConfig: { + features: { + experimentalTestSyntax: true, + }, + }, skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], @@ -688,7 +706,7 @@ export const baseTemplates = { skipTasks: ['smoke-test', 'e2e-tests', 'bench', 'vitest-integration'], }, 'lit-rsbuild/default-ts': { - name: 'Web Components Latest (RSBuild | TypeScript)', + name: 'Web Components Latest (RsBuild | TypeScript)', script: 'yarn create rsbuild -d {{beforeDir}} -t lit-ts --tools eslint', expected: { framework: 'storybook-web-components-rsbuild', @@ -697,6 +715,12 @@ export const baseTemplates = { }, modifications: { extraDependencies: ['storybook-web-components-rsbuild@^3.0.0-beta.1'], + useCsfFactory: true, + mainConfig: { + features: { + experimentalTestSyntax: true, + }, + }, skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], From 0dd85958d2191ee589f2a35052c999d65a4727f0 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 14:38:47 +0100 Subject: [PATCH 14/17] Add module mocking stories and update e2e test navigation path - Introduced a new story for module mocking in `moduleMocking.stories.ts`. - Updated the e2e test to navigate to the correct story path for module mocking. - Enhanced the `addStoriesEntry` function to include a `skipMocking` parameter for better story management. --- ...ng.stories.ts => moduleMocking.stories.ts} | 0 code/e2e-tests/module-mocking.spec.ts | 2 +- scripts/tasks/sandbox-parts.ts | 41 +++++++++++++++---- 3 files changed, 35 insertions(+), 8 deletions(-) rename code/core/template/stories/{module-mocking.stories.ts => moduleMocking.stories.ts} (100%) diff --git a/code/core/template/stories/module-mocking.stories.ts b/code/core/template/stories/moduleMocking.stories.ts similarity index 100% rename from code/core/template/stories/module-mocking.stories.ts rename to code/core/template/stories/moduleMocking.stories.ts diff --git a/code/e2e-tests/module-mocking.spec.ts b/code/e2e-tests/module-mocking.spec.ts index 6173744726fb..33420650c7b7 100644 --- a/code/e2e-tests/module-mocking.spec.ts +++ b/code/e2e-tests/module-mocking.spec.ts @@ -57,7 +57,7 @@ test.describe('module-mocking', () => { test('should assert that utils import is mocked', async ({ page }) => { const sbPage = new SbPage(page, expect); - await sbPage.navigateToStory('core/module-mocking', 'basic'); + await sbPage.navigateToStory('core/moduleMocking', 'basic'); await sbPage.viewAddonPanel('Actions'); const logItem = sbPage.panelContent().filter({ diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index c657b37c128f..12650fe59e19 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -353,15 +353,28 @@ function updateStoriesField(mainConfig: ConfigFile, isJs: boolean) { } // Add a stories field entry for the passed symlink -function addStoriesEntry(mainConfig: ConfigFile, path: string, disableDocs: boolean) { +function addStoriesEntry( + mainConfig: ConfigFile, + path: string, + disableDocs: boolean, + skipMocking: boolean +) { const stories = mainConfig.getFieldValue(['stories']) as string[]; + const basePattern = disableDocs + ? '**/*.stories.@(js|jsx|mjs|ts|tsx)' + : '**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))'; + + // When skipMocking is true and we're linking core template stories, exclude any stories + // with "mocking" in their file name (not related to docs filtering). + console.log('skipMocking', skipMocking, path); + const files = + skipMocking && path === 'core' ? basePattern.replace('**/*', '**/!(*Mocking)*') : basePattern; + const entry = { directory: slash(join('../template-stories', path)), titlePrefix: slash(path), - files: disableDocs - ? '**/*.stories.@(js|jsx|mjs|ts|tsx)' - : '**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))', + files, }; mainConfig.setFieldValue(['stories'], [...stories, entry]); @@ -379,7 +392,14 @@ async function linkPackageStories( cwd, linkInDir, disableDocs, - }: { mainConfig: ConfigFile; cwd: string; linkInDir?: string; disableDocs: boolean }, + skipMocking, + }: { + mainConfig: ConfigFile; + cwd: string; + linkInDir?: string; + disableDocs: boolean; + skipMocking: boolean; + }, variant?: string ) { const storiesFolderName = variant ? getStoriesFolderWithVariant(variant) : 'stories'; @@ -397,7 +417,7 @@ async function linkPackageStories( await ensureSymlinkOrCopy(source, target); if (!linkInDir) { - addStoriesEntry(mainConfig, packageDir, disableDocs); + addStoriesEntry(mainConfig, packageDir, disableDocs, skipMocking); } // Add `previewAnnotation` entries of the form @@ -591,6 +611,7 @@ export const addStories: Task['run'] = async ( { addon: extraAddons, disableDocs } ) => { logger.log('💃 Adding stories'); + const skipMocking = template.modifications?.skipMocking; const cwd = sandboxDir; const storiesPath = (await findFirstPath([join('src', 'stories'), 'stories'], { cwd })) || 'stories'; @@ -629,6 +650,7 @@ export const addStories: Task['run'] = async ( cwd, linkInDir: resolve(cwd, storiesPath), disableDocs, + skipMocking, }); if ( @@ -643,6 +665,7 @@ export const addStories: Task['run'] = async ( cwd, linkInDir: resolve(cwd, storiesPath), disableDocs, + skipMocking, }, sandboxSpecificStoriesFolder ); @@ -661,6 +684,7 @@ export const addStories: Task['run'] = async ( cwd, linkInDir: resolve(cwd, storiesPath), disableDocs, + skipMocking, }); } @@ -676,6 +700,7 @@ export const addStories: Task['run'] = async ( cwd, linkInDir: resolve(cwd, storiesPath), disableDocs, + skipMocking, }, sandboxSpecificStoriesFolder ); @@ -689,12 +714,14 @@ export const addStories: Task['run'] = async ( mainConfig, cwd, disableDocs, + skipMocking, }); await linkPackageStories(await workspacePath('addon test package', '@storybook/addon-vitest'), { mainConfig, cwd, disableDocs, + skipMocking, }); } @@ -741,7 +768,7 @@ export const addStories: Task['run'] = async ( if (isCoreRenderer) { const existingStories = await filterExistsInCodeDir(addonDirs, join('template', 'stories')); for (const packageDir of existingStories) { - await linkPackageStories(packageDir, { mainConfig, cwd, disableDocs }); + await linkPackageStories(packageDir, { mainConfig, cwd, disableDocs, skipMocking }); } // Add some extra settings (see above for what these do) From df5b95f4c408bc970e146977e0bc6988e1f77881 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 15:54:33 +0100 Subject: [PATCH 15/17] Remove csf-factories from non-react rsbuild-based sandboxes --- code/lib/cli-storybook/src/sandbox-templates.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index 8170a604163d..508cc588e4fe 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -552,7 +552,6 @@ export const baseTemplates = { }, modifications: { extraDependencies: ['storybook-vue3-rsbuild@^3.0.0-beta.1'], - useCsfFactory: true, mainConfig: { features: { experimentalTestSyntax: true, @@ -610,12 +609,6 @@ export const baseTemplates = { }, modifications: { extraDependencies: ['storybook-html-rsbuild@^3.0.0-beta.1'], - useCsfFactory: true, - mainConfig: { - features: { - experimentalTestSyntax: true, - }, - }, skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], @@ -715,12 +708,6 @@ export const baseTemplates = { }, modifications: { extraDependencies: ['storybook-web-components-rsbuild@^3.0.0-beta.1'], - useCsfFactory: true, - mainConfig: { - features: { - experimentalTestSyntax: true, - }, - }, skipMocking: true, }, skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], From b366e4bd71f159b3089198d1dd3f85d1793bde7f Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 16:54:17 +0100 Subject: [PATCH 16/17] Exclude e2e-dev job for rsbuild sandboxes --- .circleci/config.yml | 8 ++++---- .circleci/src/workflows/daily.yml | 2 +- .circleci/src/workflows/merged.yml | 2 +- .circleci/src/workflows/normal.yml | 2 +- code/lib/cli-storybook/src/sandbox-templates.ts | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bf70e8ea94f5..2cc4eda78dc1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -950,7 +950,7 @@ jobs: mkdir features-1 cd features-1 npm set registry http://localhost:6001 - npx create-storybook --yes --package-manager npm --features docs test a11y + npx create-storybook --yes --package-manager npm --features docs test a11y --loglevel=debug npx vitest environment: IN_STORYBOOK_SANDBOX: true @@ -1188,7 +1188,7 @@ workflows: requires: - create-sandboxes - e2e-dev: - parallelism: 32 + parallelism: 28 requires: - create-sandboxes - test-runner-production: @@ -1298,7 +1298,7 @@ workflows: requires: - create-sandboxes - e2e-dev: - parallelism: 16 + parallelism: 14 requires: - create-sandboxes - test-runner-production: @@ -1393,7 +1393,7 @@ workflows: requires: - create-sandboxes - e2e-dev: - parallelism: 9 + parallelism: 8 requires: - create-sandboxes - test-runner-production: diff --git a/.circleci/src/workflows/daily.yml b/.circleci/src/workflows/daily.yml index 7d4fbee1a568..7f02e5d6117e 100644 --- a/.circleci/src/workflows/daily.yml +++ b/.circleci/src/workflows/daily.yml @@ -50,7 +50,7 @@ jobs: requires: - create-sandboxes - e2e-dev: - parallelism: 32 + parallelism: 28 requires: - create-sandboxes - test-runner-production: diff --git a/.circleci/src/workflows/merged.yml b/.circleci/src/workflows/merged.yml index ec8cb9fd4365..b0ae80bb63ea 100644 --- a/.circleci/src/workflows/merged.yml +++ b/.circleci/src/workflows/merged.yml @@ -46,7 +46,7 @@ jobs: requires: - create-sandboxes - e2e-dev: - parallelism: 16 + parallelism: 14 requires: - create-sandboxes - test-runner-production: diff --git a/.circleci/src/workflows/normal.yml b/.circleci/src/workflows/normal.yml index ad880ff61886..a3f4ed1de6f6 100644 --- a/.circleci/src/workflows/normal.yml +++ b/.circleci/src/workflows/normal.yml @@ -46,7 +46,7 @@ jobs: requires: - create-sandboxes - e2e-dev: - parallelism: 9 + parallelism: 8 requires: - create-sandboxes - test-runner-production: diff --git a/code/lib/cli-storybook/src/sandbox-templates.ts b/code/lib/cli-storybook/src/sandbox-templates.ts index 508cc588e4fe..df497a8569b5 100644 --- a/code/lib/cli-storybook/src/sandbox-templates.ts +++ b/code/lib/cli-storybook/src/sandbox-templates.ts @@ -500,7 +500,7 @@ export const baseTemplates = { }, skipMocking: true, }, - skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'], }, 'solid-vite/default-js': { name: 'SolidJS Latest (Vite | JavaScript)', @@ -559,7 +559,7 @@ export const baseTemplates = { }, skipMocking: true, }, - skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'], }, // 'nuxt-vite/default-ts': { // name: 'Nuxt v3 (Vite | TypeScript)', @@ -611,7 +611,7 @@ export const baseTemplates = { extraDependencies: ['storybook-html-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, - skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'], }, 'svelte-vite/default-js': { name: 'Svelte Latest (Vite | JavaScript)', @@ -710,7 +710,7 @@ export const baseTemplates = { extraDependencies: ['storybook-web-components-rsbuild@^3.0.0-beta.1'], skipMocking: true, }, - skipTasks: ['e2e-tests', 'bench', 'vitest-integration'], + skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'], }, 'preact-vite/default-js': { name: 'Preact Latest (Vite | JavaScript)', From cc42c4cfcb3bc1c5ef3c2685b88c5368fbf8ae86 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 20 Nov 2025 17:14:32 +0100 Subject: [PATCH 17/17] Remove console.log --- scripts/tasks/sandbox-parts.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index 12650fe59e19..98e3de51ab48 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -367,7 +367,6 @@ function addStoriesEntry( // When skipMocking is true and we're linking core template stories, exclude any stories // with "mocking" in their file name (not related to docs filtering). - console.log('skipMocking', skipMocking, path); const files = skipMocking && path === 'core' ? basePattern.replace('**/*', '**/!(*Mocking)*') : basePattern;