Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
6860895
Builder-Webpack5: Fix @vitest/mocker resolution issue
valentinpalkovic Dec 9, 2025
a17762c
Fix @vitest/mocker resolution and add pre-build script for mocker run…
valentinpalkovic Dec 10, 2025
339a6bc
Fix export interface declaration for ThemesGlobals
icopp Dec 12, 2025
6508750
Merge branch 'next' into valentin/fix-vitest-mocker-resolution
valentinpalkovic Dec 15, 2025
f8a0aaa
Merge branch 'next' into patch-3
ndelangen Dec 24, 2025
fc4ff13
Refactor mocker-runtime build step for webpack
valentinpalkovic Jan 19, 2026
928ff55
Merge remote-tracking branch 'origin/next' into valentin/fix-vitest-m…
valentinpalkovic Jan 19, 2026
f100c4d
Fix runtime script generation
valentinpalkovic Jan 19, 2026
c3fdd40
Merge branch 'next' into valentin/fix-vitest-mocker-resolution
valentinpalkovic Jan 19, 2026
16a6630
Add module mocking interceptor for Vitest integration
valentinpalkovic Jan 19, 2026
5645273
Fix linting
valentinpalkovic Jan 19, 2026
1ae1134
Refactor mocking utilities for Vitest integration and remove deprecat…
valentinpalkovic Jan 19, 2026
006567c
Update lock file
valentinpalkovic Jan 19, 2026
38c3f85
Update dependencies in package.json and yarn.lock, including msw and …
valentinpalkovic Jan 20, 2026
695633f
Merge branch 'next' into valentin/fix-vitest-mocker-resolution
valentinpalkovic Jan 20, 2026
6a50696
Refactor Vite mocker plugin to resolve package paths and remove unuse…
valentinpalkovic Jan 20, 2026
555e816
Add code comment
valentinpalkovic Jan 20, 2026
a244e1e
Merge branch 'next' into valentin/fix-vitest-mocker-resolution
valentinpalkovic Jan 20, 2026
1b5690f
Adjust code comment
valentinpalkovic Jan 20, 2026
873a56a
Enhance Vite inject mocker plugin to emit mocker runtime file during …
valentinpalkovic Jan 20, 2026
0681faf
Cleanup
valentinpalkovic Jan 20, 2026
2fb4ad6
Merge branch 'next' into patch-3
ndelangen Jan 20, 2026
bb8a2d9
Update Vite inject mocker plugin to emit the correct mocker runtime f…
valentinpalkovic Jan 20, 2026
3cf9693
Merge branch 'next' into valentin/fix-vitest-mocker-resolution
valentinpalkovic Jan 20, 2026
c28e561
CLI: Add init telemetry for CLI integrations
shilman Jan 21, 2026
f5d9dde
Initial plan
Copilot Jan 21, 2026
6128e73
Add negative test case for create-rsbuild pattern and fix regex
Copilot Jan 21, 2026
0fbea1f
Merge pull request #33604 from storybookjs/copilot/sub-pr-33603
shilman Jan 21, 2026
f2ebc3b
Apply requested code review changes
valentinpalkovic Jan 21, 2026
918cad3
Apply requested code changes
valentinpalkovic Jan 21, 2026
5bbfcc3
Apply requested code changes
valentinpalkovic Jan 21, 2026
466824f
add docs entries to manifest debugger.
JReinhold Jan 21, 2026
a837682
Merge branch 'next' into jeppe/docs-manifest-debugger
JReinhold Jan 21, 2026
f2a087e
UI: Avoid large animation for reduced motion users
Sidnioulz Jan 14, 2026
abd4b01
Merge pull request #33315 from storybookjs/valentin/fix-vitest-mocker…
valentinpalkovic Jan 22, 2026
f696d57
Fix failure message formatting in CI workflow helper
ndelangen Jan 22, 2026
df68eaa
allow for empty `-p`, that's easier then calling the command "just ri…
ndelangen Jan 22, 2026
b6bf0df
rename
ndelangen Jan 22, 2026
94f79bf
Merge pull request #33603 from storybookjs/shilman/add-cli-init-telem…
shilman Jan 23, 2026
ef9accb
support filtering by docs
JReinhold Jan 23, 2026
09913ed
Merge branch 'jeppe/docs-manifest-debugger' of github.com:storybookjs…
JReinhold Jan 23, 2026
5ec3ef7
Merge branch 'next' into jeppe/docs-manifest-debugger
JReinhold Jan 23, 2026
a4bb7ae
Merge pull request #33607 from storybookjs/jeppe/docs-manifest-debugger
JReinhold Jan 23, 2026
b6b2532
update addon-mcp e2e tests to match new tool name.
JReinhold Jan 23, 2026
af8efd6
Merge pull request #33630 from storybookjs/jeppe/update-mcp-e2e-tests
JReinhold Jan 23, 2026
e2e1781
Merge pull request #33622 from storybookjs/norbert/fix-discord-report
ndelangen Jan 23, 2026
7ccd386
fix a typo from `wasnt'possible` to `wasn't possible`
msmx-mnakagawa Jan 26, 2026
ca2f585
fix a typo from `taht` to `that`
msmx-mnakagawa Jan 26, 2026
5c03e8c
fix typos from `overriden` to `overridden`
msmx-mnakagawa Jan 26, 2026
7a2871a
Build: Fix MCP tests on Windows
valentinpalkovic Jan 26, 2026
736b7fb
Merge pull request #33530 from storybookjs/sidnioulz/landmark-motion
ghengeveld Jan 26, 2026
b90afd7
Fix previewHref when current path does not end with a slash
ghengeveld Jan 26, 2026
00f506c
Merge pull request #33647 from storybookjs/fix-iframe-href
ghengeveld Jan 26, 2026
42de033
Avoid CSS scale transform when not actually scaling
ghengeveld Jan 26, 2026
40e7024
Merge branch 'next' into fix-typos-in-comments
jonniebigodes Jan 26, 2026
1133507
Merge pull request #33637 from msmx-mnakagawa/fix-typos-in-comments
jonniebigodes Jan 26, 2026
db4d3a1
Merge pull request #33343 from icopp/patch-3
kasperpeulen Jan 27, 2026
09dfdde
Merge branch 'next' into valentin/fix-mcp-tests-on-windows
valentinpalkovic Jan 27, 2026
50d226d
Merge pull request #33644 from storybookjs/valentin/fix-mcp-tests-on-…
valentinpalkovic Jan 27, 2026
aced2ed
Update CHANGELOG.md for v10.2.1 [skip ci]
storybook-bot Jan 27, 2026
5b37c21
Merge branch 'next' into fix-scale-1
ghengeveld Jan 27, 2026
72cb39f
Merge pull request #33651 from storybookjs/fix-scale-1
ghengeveld Jan 27, 2026
e6dae4a
Docs: Snippet fixes for supported frameworks
jonniebigodes Jan 27, 2026
0c89009
Merge branch 'next' into docs_fix_svelte_snippets
jonniebigodes Jan 27, 2026
180186e
Merge pull request #33676 from storybookjs/docs_fix_svelte_snippets
jonniebigodes Jan 27, 2026
17259a7
Write changelog for 10.3.0-alpha.1 [skip ci]
storybook-bot Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 10.2.1

- Builder-Webpack5: Fix @vitest/mocker resolution issue - [#33315](https://github.com/storybookjs/storybook/pull/33315), thanks @valentinpalkovic!
- CLI: Add init telemetry for CLI integrations - [#33603](https://github.com/storybookjs/storybook/pull/33603), thanks @shilman!

## 10.2.0

> Improved UI and story authoring ergonomics
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 10.3.0-alpha.1

- Builder-Webpack5: Fix @vitest/mocker resolution issue - [#33315](https://github.com/storybookjs/storybook/pull/33315), thanks @valentinpalkovic!
- CLI: Add init telemetry for CLI integrations - [#33603](https://github.com/storybookjs/storybook/pull/33603), thanks @shilman!
- Core: Fix `previewHref` when current path does not end with a slash - [#33647](https://github.com/storybookjs/storybook/pull/33647), thanks @ghengeveld!
- Core: Fix rendering of View Transitions in Firefox - [#33651](https://github.com/storybookjs/storybook/pull/33651), thanks @ghengeveld!
- Manifest: Add docs entries to debugger - [#33607](https://github.com/storybookjs/storybook/pull/33607), thanks @JReinhold!
- Theming: Export interface declaration for `ThemesGlobals` - [#33343](https://github.com/storybookjs/storybook/pull/33343), thanks @icopp!
- UI: Avoid large animation for reduced motion users - [#33530](https://github.com/storybookjs/storybook/pull/33530), thanks @Sidnioulz!

## 10.3.0-alpha.0

- CLI: Fix onboarding not opening - [#33609](https://github.com/storybookjs/storybook/pull/33609), thanks @ndelangen!
Expand Down
2 changes: 1 addition & 1 deletion code/addons/themes/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { definePreviewAddon } from 'storybook/internal/csf';
import * as addonAnnotations from './preview';
import type { ThemesTypes } from './types';

export type { ThemesTypes } from './types';
export type { ThemesGlobals, ThemesTypes } from './types';

export default () => definePreviewAddon<ThemesTypes>(addonAnnotations);

Expand Down
1 change: 0 additions & 1 deletion code/builders/builder-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
],
"dependencies": {
"@storybook/csf-plugin": "workspace:*",
"@vitest/mocker": "3.2.4",
"ts-dedent": "^2.0.0"
},
"devDependencies": {
Expand Down
74 changes: 16 additions & 58 deletions code/builders/builder-vite/src/plugins/vite-inject-mocker/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,35 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';

import { resolvePackageDir } from 'storybook/internal/common';
import type { ResolvedConfig } from 'vite';

import { exactRegex } from '@rolldown/pluginutils';
import { dedent } from 'ts-dedent';
import type { ResolvedConfig, ViteDevServer } from 'vite';

const entryPath = '/vite-inject-mocker-entry.js';

const entryCode = dedent`
<script type="module" src=".${entryPath}"></script>
`;

let server: ViteDevServer;
const ENTRY_PATH = '/vite-inject-mocker-entry.js';

export const viteInjectMockerRuntime = (options: {
previewConfigPath?: string | null;
}): import('vite').Plugin => {
// Get the actual file path so Vite can resolve relative imports
const mockerRuntimePath = fileURLToPath(
import.meta.resolve('storybook/internal/mocking-utils/mocker-runtime')
);

let viteConfig: ResolvedConfig;

return {
name: 'vite:storybook-inject-mocker-runtime',
enforce: 'pre',
buildStart() {
if (viteConfig.command === 'build') {
this.emitFile({
type: 'chunk',
id: join(
resolvePackageDir('storybook'),
'assets',
'server',
'mocker-runtime.template.js'
),
fileName: entryPath.slice(1),
id: mockerRuntimePath,
fileName: ENTRY_PATH.slice(1),
});
}
},
config() {
return {
optimizeDeps: {
include: ['@vitest/mocker', '@vitest/mocker/browser'],
},
resolve: {
// Aliasing necessary for package managers like pnpm, since resolving modules from a virtual module
// leads to errors, if the imported module is not a dependency of the project.
// By resolving the module to the real path, we can avoid this issue.
alias: {
'@vitest/mocker/browser': fileURLToPath(import.meta.resolve('@vitest/mocker/browser')),
'@vitest/mocker': fileURLToPath(import.meta.resolve('@vitest/mocker')),
},
},
};
},
configResolved(config) {
viteConfig = config;
},
configureServer(server_) {
server = server_;
configureServer(server) {
if (options.previewConfigPath) {
server.watcher.on('change', (file) => {
if (file === options.previewConfigPath) {
Expand All @@ -69,31 +41,17 @@ export const viteInjectMockerRuntime = (options: {
});
}
},
resolveId: {
filter: {
id: [exactRegex(entryPath)],
},
handler(id) {
if (exactRegex(id).test(entryPath)) {
return id;
}
return null;
},
},
async load(id) {
if (exactRegex(id).test(entryPath)) {
return readFileSync(
join(resolvePackageDir('storybook'), 'assets', 'server', 'mocker-runtime.template.js'),
'utf-8'
);
resolveId(source) {
if (source === ENTRY_PATH) {
return mockerRuntimePath;
}

return null;
return undefined;
},
transformIndexHtml(html: string) {
const headTag = html.match(/<head[^>]*>/);

if (headTag) {
const entryCode = `<script type="module" src="${ENTRY_PATH}"></script>`;
const headTagIndex = html.indexOf(headTag[0]);
const newHtml =
html.slice(0, headTagIndex + headTag[0].length) +
Expand Down
2 changes: 1 addition & 1 deletion code/builders/builder-vite/src/plugins/vite-mock/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { readFileSync } from 'node:fs';
import {
babelParser,
extractMockCalls,
findMockRedirect,
getAutomockCode,
getRealPath,
rewriteSbMockImportCalls,
} from 'storybook/internal/mocking-utils';
import { logger } from 'storybook/internal/node-logger';
import type { CoreConfig } from 'storybook/internal/types';

import { findMockRedirect } from '@vitest/mocker/redirect';
import { normalize } from 'pathe';
import type { Plugin, ResolvedConfig } from 'vite';

Expand Down
1 change: 0 additions & 1 deletion code/builders/builder-webpack5/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
],
"dependencies": {
"@storybook/core-webpack": "workspace:*",
"@vitest/mocker": "3.2.4",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
"cjs-module-lexer": "^1.2.3",
"css-loader": "^7.1.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { fileURLToPath } from 'node:url';
import {
babelParser,
extractMockCalls,
findMockRedirect,
getIsExternal,
resolveExternalModule,
resolveWithExtensions,
} from 'storybook/internal/mocking-utils';

import { findMockRedirect } from '@vitest/mocker/redirect';
import type { Compiler } from 'webpack';

// --- Type Definitions ---
Expand Down
10 changes: 10 additions & 0 deletions code/core/build-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,16 @@ const config: BuildEntries = {
entryPoint: './src/manager/globals-runtime.ts',
dts: false,
},
/**
* It is required to be a runtime entry point, because it is used to inject the mocker runtime
* into the preview iframe in builder-vite and builder-webpack5. To guarantee that the mocker
* runtime is transpiled correctly, code splitting needs to be disabled for this entry point.
*/
{
exportEntries: ['./internal/mocking-utils/mocker-runtime'],
entryPoint: './src/mocking-utils/mocker-runtime.js',
dts: false,
},
],
globalizedRuntime: [
{
Expand Down
2 changes: 2 additions & 0 deletions code/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
"types": "./dist/mocking-utils/index.d.ts",
"default": "./dist/mocking-utils/index.js"
},
"./internal/mocking-utils/mocker-runtime": "./dist/mocking-utils/mocker-runtime.js",
"./internal/node-logger": {
"types": "./dist/node-logger/index.d.ts",
"default": "./dist/node-logger/index.js"
Expand Down Expand Up @@ -255,6 +256,7 @@
"@types/react-syntax-highlighter": "11.0.5",
"@types/semver": "^7.7.1",
"@types/ws": "^8",
"@vitest/mocker": "3.2.4",
"@vitest/utils": "^3.2.4",
"@yarnpkg/fslib": "2.10.3",
"@yarnpkg/libzip": "2.3.0",
Expand Down
36 changes: 32 additions & 4 deletions code/core/src/core-server/utils/manifests/manifests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,30 @@ describe('manifests', () => {
expect(files['/output/manifests/components.html']).toContain('<!doctype html>');
});

it('should write HTML file when docs manifest exists', async () => {
mockManifests = {
docs: {
v: 0,
docs: {
'intro--docs': {
id: 'intro--docs',
name: 'docs',
path: './Intro.mdx',
title: 'Intro',
content: '# Introduction',
},
},
},
};

await writeManifests('/output', mockPresets);

const files = vol.toJSON();
expect(files['/output/manifests/components.html']).toBeDefined();
expect(files['/output/manifests/components.html']).toContain('<!doctype html>');
expect(files['/output/manifests/components.html']).toContain('Unattached Docs');
});

it('should handle errors when presets.apply fails', async () => {
const error = new Error('Preset application failed');
vi.mocked(mockPresets.apply).mockRejectedValue(error);
Expand Down Expand Up @@ -360,11 +384,11 @@ describe('manifests', () => {
expect(res.end).toHaveBeenCalled();
const html = (res.end as any).mock.calls[0][0];
expect(html).toContain('<!doctype html>');
expect(html).toContain('Components Manifest');
expect(html).toContain('Manifest Debugger');
expect(res.statusCode).toBeUndefined();
});

it('should return 404 message when components manifest does not exist', async () => {
it('should return 404 message when no components or docs manifest exist', async () => {
mockManifests = {
other: { data: 'value' },
};
Expand All @@ -383,7 +407,9 @@ describe('manifests', () => {

expect(res.statusCode).toBe(404);
expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'text/html; charset=utf-8');
expect(res.end).toHaveBeenCalledWith('<pre>No components manifest configured.</pre>');
expect(res.end).toHaveBeenCalledWith(
'<pre>No components or docs manifest configured.</pre>'
);
});

it('should return 404 when manifests is empty', async () => {
Expand All @@ -402,7 +428,9 @@ describe('manifests', () => {
await handler(req, res);

expect(res.statusCode).toBe(404);
expect(res.end).toHaveBeenCalledWith('<pre>No components manifest configured.</pre>');
expect(res.end).toHaveBeenCalledWith(
'<pre>No components or docs manifest configured.</pre>'
);
});

it('should handle errors with 500 status and return error HTML', async () => {
Expand Down
18 changes: 11 additions & 7 deletions code/core/src/core-server/utils/manifests/manifests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { Polka } from 'polka';
import invariant from 'tiny-invariant';

import { Tag } from '../../../shared/constants/tags';
import { renderComponentsManifest } from './render-components-manifest';
import { type DocsManifest, renderComponentsManifest } from './render-components-manifest';

async function getManifests(presets: Presets) {
const generator = await presets.apply('storyIndexGenerator');
Expand Down Expand Up @@ -37,10 +37,13 @@ export async function writeManifests(outputDir: string, presets: Presets) {
writeFile(join(outputDir, 'manifests', `${name}.json`), JSON.stringify(content))
)
);
if ('components' in manifests) {
if ('components' in manifests || 'docs' in manifests) {
await writeFile(
join(outputDir, 'manifests', 'components.html'),
renderComponentsManifest(manifests.components as ComponentsManifest)
renderComponentsManifest(
manifests.components as ComponentsManifest | undefined,
manifests.docs as DocsManifest | undefined
)
);
}
} catch (e) {
Expand Down Expand Up @@ -72,17 +75,18 @@ export function registerManifests({ app, presets }: { app: Polka; presets: Prese
app.get('/manifests/components.html', async (req, res) => {
try {
const manifests = await getManifests(presets);
const manifest = manifests.components;
const componentsManifest = manifests.components;
const docsManifest = manifests.docs as DocsManifest | undefined;

if (!manifest) {
if (!componentsManifest && !docsManifest) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(`<pre>No components manifest configured.</pre>`);
res.end(`<pre>No components or docs manifest configured.</pre>`);
return;
}

res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(renderComponentsManifest(manifest));
res.end(renderComponentsManifest(componentsManifest, docsManifest));
} catch (e) {
res.statusCode = 500;
res.setHeader('Content-Type', 'text/html; charset=utf-8');
Expand Down
Loading