Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9827e96
Centralize Vite plugins for builder-vite and addon-vitest
valentinpalkovic Feb 10, 2026
d647cb8
Refactor builder-vite: streamline plugin imports and remove unused code
valentinpalkovic Feb 11, 2026
73e8886
Fix optimize deps
valentinpalkovic Feb 11, 2026
4e54860
Refactor storybookOptimizeDepsPlugin: simplify config resolution
valentinpalkovic Feb 11, 2026
ad0c63b
Improve config resolution
valentinpalkovic Feb 11, 2026
4f0fbef
Add optimizeDeps functionality to builder-vite
valentinpalkovic Feb 11, 2026
0e3667f
Cleanup
valentinpalkovic Feb 12, 2026
59342f0
Refactor static directory handling in Vitest plugin and core server
valentinpalkovic Feb 12, 2026
9915f3d
Fix types
valentinpalkovic Feb 12, 2026
5439fe1
Remove obsolete test cases
valentinpalkovic Feb 12, 2026
36df811
Revert "Fix types"
valentinpalkovic Feb 12, 2026
5298a63
Revert "Refactor static directory handling in Vitest plugin and core …
valentinpalkovic Feb 12, 2026
d4f2b6c
Refactor Vite plugin to streamline external globals handling
valentinpalkovic Feb 12, 2026
5826751
Merge branch 'next' into valentin/encapsulate-vite-plugins
valentinpalkovic Feb 12, 2026
afe0ea3
Update virtual file names and remove unused constant
valentinpalkovic Feb 12, 2026
e3546af
Update jsdocs
valentinpalkovic Feb 12, 2026
a81220a
Cleanup docs
valentinpalkovic Feb 12, 2026
895cb72
Cleanup comments
valentinpalkovic Feb 12, 2026
47420f1
Refactor imports and remove unused code in Vitest and Vite builders
valentinpalkovic Feb 12, 2026
91ab095
Remove obsole docgen plugin
valentinpalkovic Feb 12, 2026
606bdac
Refactor modern iframe script generation and enhance project annotati…
valentinpalkovic Feb 12, 2026
2d0adaa
Refactor project annotations handling in Vite builder
valentinpalkovic Feb 12, 2026
b500e3a
Cleanup
valentinpalkovic Feb 12, 2026
aa9a688
Enhance storybookOptimizeDepsPlugin to support additional entry points
valentinpalkovic Feb 13, 2026
8af7599
Add storybookExternalGlobalsPlugin and related tests; refactor runtim…
valentinpalkovic Feb 19, 2026
fa82d19
Enhance project annotations handling with HMR support and refactor ge…
valentinpalkovic Feb 19, 2026
8117c38
Cleanup
valentinpalkovic Feb 19, 2026
6918d49
Fix linting
valentinpalkovic Feb 19, 2026
554a951
Fix wrong path
valentinpalkovic Feb 19, 2026
40177d0
Merge branch 'next' into valentin/encapsulate-vite-plugins
valentinpalkovic Feb 19, 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
1 change: 0 additions & 1 deletion code/addons/vitest/src/preset.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { readFileSync } from 'node:fs';
import { mkdir } from 'node:fs/promises';

import type { Channel } from 'storybook/internal/channels';
Expand Down
38 changes: 9 additions & 29 deletions code/addons/vitest/src/vitest-plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ import path from 'pathe';
import picocolors from 'picocolors';
import sirv from 'sirv';
import { dedent } from 'ts-dedent';
import type { PluginOption } from 'vite';

// ! Relative import to prebundle it without needing to depend on the Vite builder
// Shared plugins from builder-vite (relative import to prebundle without adding a package dependency)
import { withoutVitePlugins } from '../../../../builders/builder-vite/src/utils/without-vite-plugins';
import type { InternalOptions, UserOptions } from './types';

Expand Down Expand Up @@ -194,27 +195,25 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>

const stories = await presets.apply('stories', []);

// We can probably add more config here. See code/builders/builder-vite/src/vite-config.ts
// This one is specifically needed for code/builders/builder-vite/src/preset.ts
const commonConfig = { root: resolve(finalOptions.configDir, '..') };

const [
corePlugins,
{ storiesGlobs },
framework,
viteConfigFromStorybook,
staticDirs,
previewLevelTags,
core,
extraOptimizeDeps,
features,
] = await Promise.all([
presets.apply<PluginOption[]>('viteCorePlugins', []),
getStoryGlobsAndFiles(presets, directories),
presets.apply('framework', undefined),
presets.apply<{ plugins?: Plugin[]; root: string }>('viteFinal', commonConfig),
presets.apply('staticDirs', []),
extractTagsFromPreview(finalOptions.configDir),
presets.apply('core'),
presets.apply('optimizeViteDeps', []),
presets.apply('features', {}),
]);

Expand All @@ -230,7 +229,10 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>
}

// filter out plugins that we know are unnecesary for tests, eg. docgen plugins
const plugins = await withoutVitePlugins(viteConfigFromStorybook.plugins ?? [], pluginsToIgnore);
const plugins: Plugin[] = [
...(corePlugins as Plugin[]),
Comment thread
valentinpalkovic marked this conversation as resolved.
...(await withoutVitePlugins(viteConfigFromStorybook.plugins ?? [], pluginsToIgnore)),
];

if (finalOptions.disableAddonDocs) {
plugins.push(mdxStubPlugin);
Expand Down Expand Up @@ -382,26 +384,8 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>
},
},

envPrefix: Array.from(
new Set([...(nonMutableInputConfig.envPrefix || []), 'STORYBOOK_', 'VITE_'])
),

resolve: {
conditions: [
'storybook',
'stories',
'test',
// copying straight from https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L60
// to avoid having to maintain Vite as a dependency just for this
'module',
'browser',
'development|production',
],
},

optimizeDeps: {
include: [
...extraOptimizeDeps,
'@storybook/addon-vitest/internal/setup-file',
'@storybook/addon-vitest/internal/global-setup',
'@storybook/addon-vitest/internal/test-utils',
Expand All @@ -419,11 +403,7 @@ export const storybookTest = async (options?: UserOptions): Promise<Plugin[]> =>
},
};

// Merge config from storybook with the plugin config
const config: Omit<ViteUserConfig, 'plugins'> = mergeConfig(
baseConfig,
viteConfigFromStorybook
);
const config = mergeConfig(baseConfig, viteConfigFromStorybook);

// alert the user of problems
if ((nonMutableInputConfig.test?.include?.length ?? 0) > 0) {
Expand Down
3 changes: 1 addition & 2 deletions code/builders/builder-vite/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { Options } from 'storybook/internal/types';
import { dedent } from 'ts-dedent';
import type { InlineConfig } from 'vite';

import { sanitizeEnvVars } from './envs';
import { createViteLogger } from './logger';
import type { WebpackStatsPlugin } from './plugins';
import { hasVitePlugins } from './utils/has-vite-plugins';
Expand Down Expand Up @@ -90,7 +89,7 @@ export async function build(options: Options) {

finalConfig.customLogger ??= await createViteLogger();

await viteBuild(await sanitizeEnvVars(options, finalConfig));
await viteBuild(finalConfig);

const statsPlugin = findPlugin(
finalConfig,
Expand Down
88 changes: 12 additions & 76 deletions code/builders/builder-vite/src/codegen-modern-iframe-script.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@ import { describe, expect, it } from 'vitest';

import { generateModernIframeScriptCodeFromPreviews } from './codegen-modern-iframe-script';

const projectRoot = 'projectRoot';

describe('generateModernIframeScriptCodeFromPreviews', () => {
it('handle one annotation', async () => {
const result = await generateModernIframeScriptCodeFromPreviews({
previewAnnotations: ['/user/.storybook/preview'],
projectRoot,
frameworkName: 'frameworkName',
isCsf4: false,
});
expect(result).toMatchInlineSnapshot(`
"import { setup } from 'storybook/internal/preview/runtime';
Expand All @@ -19,18 +14,10 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {

setup();

import { composeConfigs, PreviewWeb } from 'storybook/preview-api';
import { isPreview } from 'storybook/internal/csf';
import { PreviewWeb } from 'storybook/preview-api';
import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';

import * as preview_2408 from "/user/.storybook/preview";
const getProjectAnnotations = (hmrPreviewAnnotationModules = []) => {
const configs = [
hmrPreviewAnnotationModules[0] ?? preview_2408
]
return composeConfigs(configs);
}

import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';

window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);

window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;
Expand All @@ -44,21 +31,13 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {
// importFn has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });
});

import.meta.hot.accept(["/user/.storybook/preview"], (previewAnnotationModules) => {
// getProjectAnnotations has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onGetProjectAnnotationsChanged({ getProjectAnnotations: () => getProjectAnnotations(previewAnnotationModules) });
});
};"
`);
});

it('handle one annotation CSF4', async () => {
const result = await generateModernIframeScriptCodeFromPreviews({
previewAnnotations: ['/user/.storybook/preview'],
projectRoot,
frameworkName: 'frameworkName',
isCsf4: true,
});
expect(result).toMatchInlineSnapshot(`
"import { setup } from 'storybook/internal/preview/runtime';
Expand All @@ -67,16 +46,10 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {

setup();

import { composeConfigs, PreviewWeb } from 'storybook/preview-api';
import { isPreview } from 'storybook/internal/csf';
import { PreviewWeb } from 'storybook/preview-api';
import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';

import * as preview_2408 from "/user/.storybook/preview";
const getProjectAnnotations = (hmrPreviewAnnotationModules = []) => {
const preview = hmrPreviewAnnotationModules[0] ?? preview_2408;
return preview.default.composed;
}

import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';

window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);

window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;
Expand All @@ -90,21 +63,13 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {
// importFn has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });
});

import.meta.hot.accept(["/user/.storybook/preview"], (previewAnnotationModules) => {
// getProjectAnnotations has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onGetProjectAnnotationsChanged({ getProjectAnnotations: () => getProjectAnnotations(previewAnnotationModules) });
});
};"
`);
});

it('handle multiple annotations', async () => {
const result = await generateModernIframeScriptCodeFromPreviews({
previewAnnotations: ['/user/previewAnnotations1', '/user/.storybook/preview'],
projectRoot,
frameworkName: 'frameworkName',
isCsf4: false,
});
expect(result).toMatchInlineSnapshot(`
"import { setup } from 'storybook/internal/preview/runtime';
Expand All @@ -113,20 +78,10 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {

setup();

import { composeConfigs, PreviewWeb } from 'storybook/preview-api';
import { isPreview } from 'storybook/internal/csf';
import { PreviewWeb } from 'storybook/preview-api';
import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';

import * as previewAnnotations1_2526 from "/user/previewAnnotations1";
import * as preview_2408 from "/user/.storybook/preview";
const getProjectAnnotations = (hmrPreviewAnnotationModules = []) => {
const configs = [
hmrPreviewAnnotationModules[0] ?? previewAnnotations1_2526,
hmrPreviewAnnotationModules[1] ?? preview_2408
]
return composeConfigs(configs);
}

import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';

window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);

window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;
Expand All @@ -140,21 +95,13 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {
// importFn has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });
});

import.meta.hot.accept(["/user/previewAnnotations1","/user/.storybook/preview"], (previewAnnotationModules) => {
// getProjectAnnotations has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onGetProjectAnnotationsChanged({ getProjectAnnotations: () => getProjectAnnotations(previewAnnotationModules) });
});
};"
`);
});

it('handle multiple annotations CSF4', async () => {
const result = await generateModernIframeScriptCodeFromPreviews({
previewAnnotations: ['/user/previewAnnotations1', '/user/.storybook/preview'],
projectRoot,
frameworkName: 'frameworkName',
isCsf4: true,
});
expect(result).toMatchInlineSnapshot(`
"import { setup } from 'storybook/internal/preview/runtime';
Expand All @@ -163,16 +110,10 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {

setup();

import { composeConfigs, PreviewWeb } from 'storybook/preview-api';
import { isPreview } from 'storybook/internal/csf';
import { PreviewWeb } from 'storybook/preview-api';
import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';

import * as preview_2408 from "/user/.storybook/preview";
const getProjectAnnotations = (hmrPreviewAnnotationModules = []) => {
const preview = hmrPreviewAnnotationModules[0] ?? preview_2408;
return preview.default.composed;
}

import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';

window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);

window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;
Expand All @@ -186,11 +127,6 @@ describe('generateModernIframeScriptCodeFromPreviews', () => {
// importFn has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });
});

import.meta.hot.accept(["/user/.storybook/preview"], (previewAnnotationModules) => {
// getProjectAnnotations has changed so we need to patch the new one in
window.__STORYBOOK_PREVIEW__.onGetProjectAnnotationsChanged({ getProjectAnnotations: () => getProjectAnnotations(previewAnnotationModules) });
});
};"
`);
});
Expand Down
Loading
Loading