Skip to content

Comments

Builder-Vite: Centralize Vite plugins for builder-vite and addon-vitest#33819

Merged
valentinpalkovic merged 30 commits intonextfrom
valentin/encapsulate-vite-plugins
Feb 19, 2026
Merged

Builder-Vite: Centralize Vite plugins for builder-vite and addon-vitest#33819
valentinpalkovic merged 30 commits intonextfrom
valentin/encapsulate-vite-plugins

Conversation

@valentinpalkovic
Copy link
Contributor

@valentinpalkovic valentinpalkovic commented Feb 10, 2026

Closes #33813

What I did

This PR refactors the @storybook/builder-vite plugin architecture to move core logic into a more modular, plugin-based structure.

Key Changes

1. Modularization of Vite Plugins
Previously, much of the Vite configuration (resolve conditions, environment variables, fs-allow rules) was hardcoded within the builder's vite-config.ts. These have been extracted into self-contained plugins:

  • storybookConfigPlugin: Handles resolve conditions (storybook, stories, test), envPrefix (VITE_, STORYBOOK_), and filesystem access.
  • storybookProjectAnnotationsPlugin: Manages the virtual module for composed project annotations (getProjectAnnotations).
  • storybookRuntimePlugin: Handles external globals and environment variable injection.

2. Introduction of viteCorePlugins Preset
A new viteCorePlugins preset has been added to builder-vite/src/preset.ts. (We don't want to use viteFinal to be able to clearly distinguish what is a shareable core plugin and what is config contributed by other addons/frameworks/user config - This was requested by Jeppe). This serves as the single source of truth for the Vite setup required to run Storybook code, and it can now be applied by both the standard builder and the addon-vitest.

3. Refined Virtual Module Handling
The project annotations logic has been moved out of the monolithic codeGeneratorPlugin into a dedicated virtual module: virtual:/@storybook/builder-vite/project-annotations.js. This allows tests and external tools to access composed annotations. The project annotations will be re-used in @storybook/addon-vitest in SB 11, since it is considered a breaking change because it might conflict with the user's existing .storybook/vitest.setup.ts file.

4. Cleanups and Optimization

  • Removed sanitizeEnvVars in favor of the new storybookRuntimePlugin, which handles define injection via the standard Vite plugin config hook.
  • Dependency Optimization: Simplified getOptimizeDeps logic and moved it into a plugin-driven approach.

Impact on @storybook/addon-vitest
By leveraging the new viteCorePlugins preset, addon-vitest can now automatically stay in sync with the builder's configuration for resolve conditions, globals, and docgen, reducing the maintenance burden and preventing configuration drift.

Checklist for Contributors

Testing

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

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

Manual testing

Manual testing should cover:

  • HMR of preview files
  • addon-vitest general functionality
  • proper setting of optimize deps for both, Storybook and Story Tests powered by Vitest

Documentation

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

Checklist for Maintainers

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

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

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

🦋 Canary release

This pull request has been released as version 0.0.0-pr-33819-sha-40177d0f. Try it out in a new sandbox by running npx storybook@0.0.0-pr-33819-sha-40177d0f sandbox or in an existing project with npx storybook@0.0.0-pr-33819-sha-40177d0f upgrade.

More information
Published version 0.0.0-pr-33819-sha-40177d0f
Triggered by @valentinpalkovic
Repository storybookjs/storybook
Branch valentin/encapsulate-vite-plugins
Commit 40177d0f
Datetime Thu Feb 19 13:56:41 UTC 2026 (1771509401)
Workflow run 22184698620

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

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

Summary by CodeRabbit

  • New Features

    • Modular Vite plugins for Storybook (config, runtime, entry, optimize-deps, project annotations) and virtual module for project annotations.
    • Unified codegen for modern iframe to import project annotations.
  • Refactor

    • Simplified Vite config assembly and optimize-deps flow; moved builder-specific settings into dedicated plugin.
    • Explicit plugin exports and tighter type assertions.
  • Chores

    • Removed unused imports and cleaned up exports.

@valentinpalkovic valentinpalkovic self-assigned this Feb 10, 2026
@valentinpalkovic valentinpalkovic added maintenance User-facing maintenance tasks ci:normal labels Feb 10, 2026
@nx-cloud
Copy link

nx-cloud bot commented Feb 10, 2026

View your CI Pipeline Execution ↗ for commit 40177d0

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ❌ Failed 5m 22s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-19 15:59:25 UTC

- Removed commented-out import for `getProjectAnnotations` in `codegen-modern-iframe-script.ts`.
- Eliminated the direct call to `storybookRuntimePlugin` in `preset.ts`, now included in `vite-config.ts` for better organization.
- Cleaned up `sandbox-parts.ts` by removing unnecessary `beforeAll` import while maintaining functionality for CSF4 support.
- Updated the `storybookOptimizeDepsPlugin` to directly resolve the configuration with an empty object instead of destructuring from the provided config. This change streamlines the plugin's logic for better clarity and maintainability.
- Introduced a new `optimizeDeps.ts` file containing the `getOptimizeDeps` function to handle dependency optimization for Vite.
- Updated `vite-server.ts` to utilize `getOptimizeDeps` for improved dependency inclusion in the Vite server configuration.
- Refactored `storybookOptimizeDepsPlugin` to streamline the inclusion of extra dependencies without redundant resolution logic.
- Removed unused asyncFilter function from `storybookOptimizeDepsPlugin` for cleaner codebase.
@valentinpalkovic valentinpalkovic marked this pull request as ready for review February 11, 2026 20:55
@valentinpalkovic valentinpalkovic marked this pull request as draft February 11, 2026 20:58
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors builder-vite and addon-vitest plugin/preset architecture: introduces viteCorePlugins and multiple new builder-vite Vite plugins (config, entry, optimize-deps, project-annotations, runtime), removes sanitizeEnvVars, simplifies optimizeDeps and codegen paths, and updates vitest plugin to fetch and merge core Vite plugins.

Changes

Cohort / File(s) Summary
Builder-Vite core plugins
code/builders/builder-vite/src/plugins/storybook-config-plugin.ts, code/builders/builder-vite/src/plugins/storybook-entry-plugin.ts, code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.ts, code/builders/builder-vite/src/plugins/storybook-project-annotations-plugin.ts, code/builders/builder-vite/src/plugins/storybook-runtime-plugin.ts
Adds five new plugins implementing Storybook-specific Vite behavior: config, entry composition, optimizeDeps (dev), project-annotations virtual module, and runtime env/globals injection.
Plugin exports & typing
code/builders/builder-vite/src/plugins/index.ts, code/builders/builder-vite/src/plugins/code-generator-plugin.ts, code/builders/builder-vite/src/plugins/inject-export-order-plugin.ts, code/builders/builder-vite/src/plugins/strip-story-hmr-boundaries.ts
Replaces wildcard exports with explicit named exports; refines plugin return typing using } satisfies Plugin; assertions and removes some explicit return type annotations.
Preset / plugin composition
code/builders/builder-vite/src/preset.ts, code/addons/vitest/src/vitest-plugin/index.ts
Renames viteFinalviteCorePlugins returning PluginOption[]; preset now composes core plugin array (storybookConfigPlugin, storybookOptimizeDepsPlugin, storybookProjectAnnotationsPlugin) and conditionally injects mocker plugins. addon-vitest now fetches corePlugins via presets.apply('viteCorePlugins', []) and merges them into final plugins list.
Optimize deps & envs simplification
code/builders/builder-vite/src/optimizeDeps.ts, code/builders/builder-vite/src/envs.ts
Removes StoryIndex/Options dependency from getOptimizeDeps (signature now only takes config), drops sanitizeEnvVars export and logic, and simplifies optimizeDeps/include assembly.
Build & server flow
code/builders/builder-vite/src/build.ts, code/builders/builder-vite/src/vite-server.ts
Removes sanitizeEnvVars usage from build and server paths; server now computes optimizeDeps via getOptimizeDeps(commonCfg) and merges includes into the InlineConfig before creating the server.
Codegen & virtual modules
code/builders/builder-vite/src/codegen-project-annotations.ts, code/builders/builder-vite/src/codegen-modern-iframe-script.ts
Adds project annotations codegen utilities; simplifies iframe script generation to import getProjectAnnotations from the project-annotations virtual module, removing per-preview import generation and CSF conditional generation.
Vite config refactor & tests
code/builders/builder-vite/src/vite-config.ts, code/builders/builder-vite/src/vite-config.test.ts
Refactors config to rely on viteCorePlugins and a builder-specific config plugin for root/base/cacheDir; updates tests to assert plugin hook behavior, resolve conditions, and fs allow-list handling.
Vitest & misc cleanup
code/addons/vitest/src/preset.ts, scripts/tasks/sandbox-parts.ts
Removes unused imports (readFileSync, beforeAll) and adjusts vitest plugin composition to include corePlugins fetched from presets.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Presets
participant BuilderVite as Builder-Vite (preset/plugins)
participant Vite as Vite (server/build)
participant VirtualMod as ProjectAnnotations (virtual module)
Presets->>BuilderVite: apply('viteCorePlugins') -> returns corePlugins[]
BuilderVite->>Vite: assemble config + plugins (corePlugins + runtime/entry/etc.)
Vite->>Vite: getOptimizeDeps(commonCfg) -> optimizeDeps.include
Vite->>Vite: createServer / build with merged config
Vite->>VirtualMod: resolve virtual:/@storybook/.../project-annotations.js
VirtualMod->>Vite: load -> generateProjectAnnotationsCode(...) (code + HMR hooks)
Vite->>Preview: HMR notify -> window.STORYBOOK_PREVIEW update

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs


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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/builders/builder-vite/src/vite-config.test.ts (1)

1-44: ⚠️ Potential issue | 🟡 Minor

Align Vitest mocks with the repo's spy-mocking rules

vi.mock('vite', ...) is missing the spy: true option. Additionally, mock implementations must be set in a beforeEach block, not inline within test cases.

Required changes
-import { describe, expect, it, vi } from 'vitest';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
@@
-vi.mock('vite', async (importOriginal) => ({
-  ...(await importOriginal<typeof import('vite')>()),
-  loadConfigFromFile: vi.fn(async () => ({})),
-  defaultClientConditions: undefined,
-}));
+vi.mock(
+  'vite',
+  async (importOriginal) => ({
+    ...(await importOriginal<typeof import('vite')>()),
+    loadConfigFromFile: vi.fn(async () => ({})),
+    defaultClientConditions: undefined,
+  }),
+  { spy: true }
+);
 const loadConfigFromFileMock = vi.mocked(loadConfigFromFile);
+
+beforeEach(() => {
+  loadConfigFromFileMock.mockResolvedValue({
+    config: {},
+    path: '',
+    dependencies: [],
+  });
+});
@@
-    loadConfigFromFileMock.mockReturnValueOnce(
-      Promise.resolve({
-        config: {},
-        path: '',
-        dependencies: [],
-      })
-    );

Per the spy-mocking rules: mocks must use spy: true, all mock behaviors must be in beforeEach blocks, and inline mock implementations within test cases must be avoided.

🤖 Fix all issues with AI agents
In `@code/builders/builder-vite/src/codegen-project-annotations.ts`:
- Around line 95-97: The current hash function (hash) in
codegen-project-annotations.ts is weak (sums char codes) and can collide for
permutations; replace it with a robust deterministic string hash (e.g., FNV-1a
or a cryptographic hash like SHA-1/SHA-256 via crypto.createHash) so returned
values are hex digests rather than simple integers, and update any callers
expecting the old numeric value to accept the new string digest; ensure the
implementation remains deterministic and performant for filenames and adjust
tests if they assert the previous numeric output.

In `@code/builders/builder-vite/src/plugins/storybook-config-plugin.ts`:
- Around line 53-69: The envPrefix logic in async config(config) of
storybook-config-plugin.ts currently discards user-defined config.envPrefix;
change it to merge and deduplicate user prefixes with 'STORYBOOK_' instead of
replacing them: if config.envPrefix exists, produce an array that includes all
entries from config.envPrefix plus 'STORYBOOK_' (only add 'STORYBOOK_' if not
already present), otherwise keep the fallback ['VITE_', 'STORYBOOK_']; ensure
the final value is assigned to envPrefix in the returned config object.

In `@code/builders/builder-vite/src/plugins/storybook-runtime-plugin.ts`:
- Around line 57-66: In storybookRuntimePlugin, presets.apply is incorrectly
typed as presets.apply<Promise<Builder_EnvsRaw>>('env') causing a double Promise
so awaited envs is still a Promise; change the generic to the raw type (e.g.,
presets.apply<Builder_EnvsRaw>('env') or
presets.apply<Record<string,string>>('env')) so await returns the actual env
object, then stringifyProcessEnvs(envs, config.envPrefix) and Object.keys(envs)
will operate on the real object; update the call site in storybookRuntimePlugin
and ensure the envs variable usage (stringifyProcessEnvs, Object.keys) assumes
the non-Promise shape.

In `@code/builders/builder-vite/src/preset.ts`:
- Around line 13-30: The JSDoc lists "Docgen plugin" and "Runtime plugin" but
the preset's returned plugins array in preset.ts does not include
implementations for those; either remove or update those entries in the comment
to match reality, or add the corresponding plugin instances to the returned
array (e.g. the docgen plugin and the runtime transformation plugin) and ensure
their factory names match existing exports (use the actual plugin factory names
used elsewhere in the repo, e.g. docgenPlugin / runtimePlugin or the equivalent
functions), updating the comment text if you choose to implement them so the
docs and the returned plugins remain consistent.
- Around line 37-42: The computed externals object in preset.ts (built from
globalsNameReferenceMap and conditionally adding '@storybook/addon-docs/blocks'
when build?.test?.disableBlocks is true) is never used; update
storybookRuntimePlugin to accept an externals parameter (change its signature in
storybook-runtime-plugin.ts to accept externals: Record<string,string>), modify
its internal references to use that externals argument instead of directly
reading globalsNameReferenceMap, and then pass the computed externals from
preset.ts into the call to storybookRuntimePlugin so the disableBlocks override
is applied.
🧹 Nitpick comments (3)
code/builders/builder-vite/src/vite-server.ts (1)

15-25: Deduplicate optimizeDeps.include when merging

getOptimizeDeps already appends commonCfg.optimizeDeps?.include; merging the same list again can introduce duplicates and redundant pre-bundling. Consider deduping (or relying solely on optimizeDeps.include).

♻️ Suggested change
   const config: InlineConfig & { server: ServerOptions } = {
     ...commonCfg,
     // Set up dev server
     optimizeDeps: {
       ...commonCfg.optimizeDeps,
-      include: [...(commonCfg.optimizeDeps?.include || []), ...optimizeDeps.include],
+      include: [
+        ...new Set([...(commonCfg.optimizeDeps?.include ?? []), ...optimizeDeps.include]),
+      ],
     },
code/addons/vitest/src/vitest-plugin/index.ts (1)

33-237: Consider flattening viteCorePlugins output to handle the full PluginOption type spec

While the current viteCorePlugins implementation returns a flat array, its type signature (PluginOption[]) permits nested arrays and falsy entries per Vite's type definitions. The direct cast (corePlugins as Plugin[]) bypasses this type safety. For defensive robustness, flatten and filter before spreading.

♻️ Suggested change
-  const plugins: Plugin[] = [
-    ...(corePlugins as Plugin[]),
-    ...(await withoutVitePlugins(viteConfigFromStorybook.plugins ?? [], pluginsToIgnore)),
-  ];
+  const corePlugins = (corePlugins ?? []).flat().filter(Boolean) as Plugin[];
+
+  const plugins: Plugin[] = [
+    ...corePlugins,
+    ...(await withoutVitePlugins(viteConfigFromStorybook.plugins ?? [], pluginsToIgnore)),
+  ];
code/builders/builder-vite/src/codegen-project-annotations.ts (1)

56-69: Consider handling the empty annotations edge case.

If all entries in previewAnnotations are undefined and get filtered out, previewAnnotationURLs will be empty. This causes variables[variables.length - 1] (line 71) to return undefined, which would generate invalid code for the CSF4 path.

While generateProjectAnnotationsCode always appends previewOrConfigFile (which may be undefined), and CSF4 detection requires a valid preview file, an explicit guard could improve robustness for generateProjectAnnotationsCodeFromPreviews as a public API.

🛡️ Optional: Add early return for empty annotations
 export function generateProjectAnnotationsCodeFromPreviews(options: {
   previewAnnotations: (PreviewAnnotation | undefined)[];
   projectRoot: string;
   frameworkName: string;
   isCsf4: boolean;
 }) {
   const { projectRoot } = options;
   const previewAnnotationURLs = options.previewAnnotations
     .filter((path) => path !== undefined)
     .map((path) => processPreviewAnnotation(path, projectRoot));
 
+  if (previewAnnotationURLs.length === 0) {
+    return dedent`
+      export function getProjectAnnotations() {
+        return {};
+      }
+    `.trim();
+  }
+
   const variables: string[] = [];

Comment on lines +95 to +97
function hash(value: string) {
return value.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Weak hash function can produce collisions.

This hash function sums character codes, so permutations of the same characters produce identical hashes (e.g., "abc" and "cba" both hash to 294). While the filename prefix provides some disambiguation, consider a more robust approach if uniqueness is important.

🔧 Suggested improvement using a simple string hash
 function hash(value: string) {
-  return value.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
+  // Simple djb2-style hash for better distribution
+  return value.split('').reduce((acc, char) => ((acc << 5) - acc + char.charCodeAt(0)) | 0, 5381) >>> 0;
 }
🤖 Prompt for AI Agents
In `@code/builders/builder-vite/src/codegen-project-annotations.ts` around lines
95 - 97, The current hash function (hash) in codegen-project-annotations.ts is
weak (sums char codes) and can collide for permutations; replace it with a
robust deterministic string hash (e.g., FNV-1a or a cryptographic hash like
SHA-1/SHA-256 via crypto.createHash) so returned values are hex digests rather
than simple integers, and update any callers expecting the old numeric value to
accept the new string digest; ensure the implementation remains deterministic
and performant for filenames and adjust tests if they assert the previous
numeric output.

Comment on lines 37 to 42
const build = await options.presets.apply('build');
const externals: Record<string, string> = { ...globalsNameReferenceMap };

const coreOptions = await options.presets.apply('core');
if (build?.test?.disableBlocks) {
externals['@storybook/addon-docs/blocks'] = '__STORYBOOK_BLOCKS_EMPTY_MODULE__';
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, read the full preset.ts file to understand the context
cat -n code/builders/builder-vite/src/preset.ts

Repository: storybookjs/storybook

Length of output: 2919


🏁 Script executed:

# Search for runtime plugin and externals usage patterns
rg -n 'storybookRuntimePlugin|externals' code/builders/builder-vite/src/ -A 2 -B 2

Repository: storybookjs/storybook

Length of output: 6798


🏁 Script executed:

# Check if there are any runtime plugins in the codebase that handle externals
rg -n 'runtimePlugin' code/builders/builder-vite/ -A 3

Repository: storybookjs/storybook

Length of output: 47


🏁 Script executed:

# Look for how other presets handle externals or similar configurations
fd -t f 'preset.ts' code/builders/ -x grep -l 'externals' {}

Repository: storybookjs/storybook

Length of output: 105


🏁 Script executed:

# Read the storybook-runtime-plugin.ts to understand how it's meant to be used
cat -n code/builders/builder-vite/src/plugins/storybook-runtime-plugin.ts | head -80

Repository: storybookjs/storybook

Length of output: 3190


🏁 Script executed:

# Check vite-config.ts to see how storybookRuntimePlugin and corePlugins are called
cat -n code/builders/builder-vite/src/vite-config.ts | sed -n '70,85p'

Repository: storybookjs/storybook

Length of output: 729


🏁 Script executed:

# Check if externals parameter should be passed to storybookRuntimePlugin
rg -A 10 'function storybookRuntimePlugin' code/builders/builder-vite/src/plugins/storybook-runtime-plugin.ts

Repository: storybookjs/storybook

Length of output: 554


🏁 Script executed:

# Check if disableBlocks is used elsewhere and what it's supposed to do
rg -n 'disableBlocks' code/builders/builder-vite/ -B 2 -A 2

Repository: storybookjs/storybook

Length of output: 902


🏁 Script executed:

# Check the StorybookRuntimePluginOptions interface more carefully
cat -n code/builders/builder-vite/src/plugins/storybook-runtime-plugin.ts | sed -n '16,41p'

Repository: storybookjs/storybook

Length of output: 1179


🏁 Script executed:

# Check how externalGlobalsPlugin uses the externals parameter
cat -n code/builders/builder-vite/src/plugins/external-globals-plugin.ts | sed -n '35,70p'

Repository: storybookjs/storybook

Length of output: 1797


🏁 Script executed:

# Final confirmation: check all callers of storybookRuntimePlugin
rg -n 'storybookRuntimePlugin(' code/builders/builder-vite/ --type ts

Repository: storybookjs/storybook

Length of output: 161


🏁 Script executed:

# Verify the signature hasn't been updated elsewhere
grep -r 'export.*function storybookRuntimePlugin' code/builders/builder-vite/

Repository: storybookjs/storybook

Length of output: 215


🏁 Script executed:

# Check if StorybookRuntimePluginOptions interface is used anywhere
rg -n 'StorybookRuntimePluginOptions' code/builders/builder-vite/

Repository: storybookjs/storybook

Length of output: 183


externals is computed but never used—this prevents the disableBlocks override from being applied.

The externals object is built from globalsNameReferenceMap with a conditional override for @storybook/addon-docs/blocks when tests disable blocks, but it's never passed to the runtime plugin. The storybookRuntimePlugin() function is hardcoded to use globalsNameReferenceMap directly (line 58 of storybook-runtime-plugin.ts), with no way to accept the computed externals including the blocks override. Update the storybookRuntimePlugin signature to accept externals as a parameter and pass the computed value from preset.ts.

🤖 Prompt for AI Agents
In `@code/builders/builder-vite/src/preset.ts` around lines 37 - 42, The computed
externals object in preset.ts (built from globalsNameReferenceMap and
conditionally adding '@storybook/addon-docs/blocks' when
build?.test?.disableBlocks is true) is never used; update storybookRuntimePlugin
to accept an externals parameter (change its signature in
storybook-runtime-plugin.ts to accept externals: Record<string,string>), modify
its internal references to use that externals argument instead of directly
reading globalsNameReferenceMap, and then pass the computed externals from
preset.ts into the call to storybookRuntimePlugin so the disableBlocks override
is applied.

@storybook-app-bot
Copy link

storybook-app-bot bot commented Feb 12, 2026

Package Benchmarks

Commit: 40177d0, ran on 20 February 2026 at 08:20:48 UTC

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

@storybook/addon-vitest

Before After Difference
Dependency count 2 2 0
Self size 402 KB 391 KB 🎉 -11 KB 🎉
Dependency size 338 KB 338 KB 0 B
Bundle Size Analyzer Link Link

@valentinpalkovic valentinpalkovic changed the title Centralize Vite plugins for builder-vite and addon-vitest Builder-Vite: Centralize Vite plugins for builder-vite and addon-vitest Feb 12, 2026
This reverts commit 9915f3d.
- Moved the external globals logic into the `storybookRuntimePlugin` function.
- Removed redundant external globals mapping from `viteCorePlugins`.
- Added conditional handling for `@storybook/addon-docs/blocks` based on build configuration.
@valentinpalkovic valentinpalkovic marked this pull request as ready for review February 12, 2026 11:04
- Removed the `VIRTUAL_PROJECT_ANNOTATIONS_FILE` from `SB_VIRTUAL_FILES`.
- Updated the `VIRTUAL_ID` in the `storybook-project-annotations-plugin` to directly use the virtual file path string instead of the constant.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@code/builders/builder-vite/src/preset.ts`:
- Around line 30-33: Remove the unused existing parameter from the
viteCorePlugins signature and all call sites (they currently pass []), and
update the JSDoc for viteCorePlugins to remove references to "Docgen plugin" and
"Runtime plugin" and instead accurately describe only the plugins actually
returned by the function; locate the function named viteCorePlugins and its
callers to change the signature and calls, and edit the comment block above
viteCorePlugins to list the correct returned plugins.
🧹 Nitpick comments (1)
code/builders/builder-vite/src/plugins/storybook-config-plugin.ts (1)

59-71: Consider returning a config object instead of mutating directly.

The plugin mutates config.server.fs.allow via push(). While Vite tolerates this, returning a merged config object is the recommended pattern for better predictability and debugging.

♻️ Suggested refactor
     {
       name: 'storybook:allow-storybook-dir',
       enforce: 'post',
       config(config) {
         // If there is NO allow list then Vite allows anything in the root directory.
         // If there IS an allow list then Vite only allows the listed directories.
         // We add the storybook config directory only if there's already an allow list,
         // to avoid disallowing the root unless it's already restricted.
         if (config?.server?.fs?.allow) {
-          config.server.fs.allow.push(options.configDir);
+          return {
+            server: {
+              fs: {
+                allow: [...config.server.fs.allow, options.configDir],
+              },
+            },
+          };
         }
       },
     },

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/storybookjs/storybook/issues/comments/3887226769","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nRefactors builder-vite to a modular plugin architecture: introduces multiple new Vite plugins (config, optimize-deps, docgen, entry, runtime, project-annotations), renames `viteFinal` → `viteCorePlugins` (returns PluginOption[]), removes `sanitizeEnvVars`, simplifies optimizeDeps and related call sites, and updates vitest integration to include core plugins.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**New Plugin Modules** <br> `code/builders/builder-vite/src/plugins/storybook-config-plugin.ts`, `.../storybook-optimize-deps-plugin.ts`, `.../storybook-docgen-plugin.ts`, `.../storybook-entry-plugin.ts`, `.../storybook-runtime-plugin.ts`, `.../storybook-project-annotations-plugin.ts`|Adds six builder-specific Vite plugins handling config hooks, optimizeDeps computation, docgen/CSF enrichment, composite entry generation, runtime env/global handling, and a virtual project-annotations module.|\n|**Codegen for Project Annotations** <br> `code/builders/builder-vite/src/codegen-project-annotations.ts`|New module that generates the virtual PROJECT_ANNOTATIONS_FILE exports, composing preview annotations and emitting CSF4-aware runtime code.|\n|**Preset / Core Plugin Surface** <br> `code/builders/builder-vite/src/preset.ts`|Renames `viteFinal` → `viteCorePlugins`, changes signature to return `PluginOption[]`, and wires core plugins (`storybookConfigPlugin`, `storybookOptimizeDepsPlugin`, `storybookProjectAnnotationsPlugin`) into presets.|\n|**Vite Config & Server** <br> `code/builders/builder-vite/src/vite-config.ts`, `.../vite-server.ts`, `.../vite-config.test.ts`|Reworks config composition to consume corePlugins + builder plugins (runtime, docgen, entry); moves env/resolve/cache logic into plugins; updates tests to validate plugin hook behavior and FS allow-list handling.|\n|**OptimizeDeps & Env Utilities** <br> `code/builders/builder-vite/src/optimizeDeps.ts`, `.../envs.ts`|Removes `Options` from `getOptimizeDeps` signature, drops StoryIndex dependency and `sanitizeEnvVars` implementation; returns typed optimizeDeps object; `stringifyProcessEnvs` remains.|\n|**Build & Server Call Sites** <br> `code/builders/builder-vite/src/build.ts`, `code/builders/builder-vite/src/vite-server.ts`|Removes calls to `sanitizeEnvVars`; passes final Vite config directly to build/server creation; integrates new optimizeDeps usage.|\n|**Plugin Exports & Typing Refinements** <br> `code/builders/builder-vite/src/plugins/index.ts`, `.../code-generator-plugin.ts`, `.../inject-export-order-plugin.ts`, `.../strip-story-hmr-boundaries.ts`|Switches wildcard exports to explicit named exports; adds `} satisfies Plugin` type assertions and removes some explicit return type annotations to align typing style.|\n|**Vitest Addon Integration** <br> `code/addons/vitest/src/vitest-plugin/index.ts`|Fetches `corePlugins` via `presets.apply('viteCorePlugins', [])` and merges them into the assembled plugins; removes `extraOptimizeDeps` usage and some inlined vite config fields.|\n|**Scripts / Generated Templates** <br> `scripts/tasks/sandbox-parts.ts`|Removes unused `beforeAll` import from generated sandbox setup templates. |\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant Presets as Presets (presets.apply)\n    participant Preset as viteCorePlugins\n    participant Core as Core Plugins\n    participant Builder as Builder Plugins\n    participant Vite as Vite (createServer / build)\n    rect rgba(135,206,250,0.5)\n    Presets->>Preset: apply('viteCorePlugins') -> plugin array\n    end\n    rect rgba(144,238,144,0.5)\n    Preset->>Core: assemble core pluginOption[] (storybookConfigPlugin, optimize-deps, project-annotations ...)\n    Preset->>Builder: include builder plugins (runtime, docgen, entry, webpack-stats)\n    end\n    rect rgba(255,228,181,0.5)\n    Core->>Vite: provide plugins + inline config (optimizeDeps merged)\n    Builder->>Vite: provide additional plugins (env, entry, docgen)\n    Vite->>Vite: createServer / viteBuild uses merged plugins & config\n    end\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~50 minutes\n\n## Possibly related PRs\n\n- storybookjs/storybook#33479 — Modifies the same vitest plugin file and plugin-assembly logic used to fetch and merge `viteCorePlugins`.  \n- storybookjs/storybook#32921 — Related changes that wire mocker runtime/plugins into builder-vite's preset/plugin composition.  \n- storybookjs/storybook#32813 — Adds/relates to `storybookDocgenPlugin` and the `experimental_enrichCsf` plumbing used by the new docgen plugin.\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}}}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.ts`:
- Around line 25-32: The plugin currently overwrites optimizeDeps.entries with
only Storybook entries; instead merge Storybook entries with any user-provided
entries so existing Vite inference or explicit hints aren't lost. Update the
object returned in the function that builds optimizeDeps to combine
getUniqueImportPaths(index) with config.optimizeDeps?.entries (e.g., concat or
dedupe) and set optimizeDeps.entries to that merged array, while leaving the
include merge logic (extraOptimizeDeps + config.optimizeDeps?.include)
unchanged.

- Removed unused `readFileSync` import in `preset.ts`.
- Simplified imports in `envs.ts` by removing the `Options` type.
- Cleaned up imports in `storybook-config-plugin.ts` by removing the unused `resolvePathInStorybookCache` and adjusting the `Plugin` import.
…ons plugin

- Simplified the `generateModernIframeScriptCode` function by removing unused parameters and code related to preview annotations.
- Updated the `generateModernIframeScriptCodeFromPreviews` function to utilize the new `getProjectAnnotations` import.
- Enhanced the `storybookProjectAnnotationsPlugin` to include HMR support for project annotations, allowing for dynamic updates during development.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@code/builders/builder-vite/src/codegen-modern-iframe-script.ts`:
- Line 7: The generated import uses RESOLVED_VIRTUAL_ID (which contains the
internal '\0' prefix) instead of the public virtual ID; update the code that
builds the import string to use the public ID by either importing and using
VIRTUAL_ID from the plugin or by calling
getOriginalVirtualModuleId(RESOLVED_VIRTUAL_ID) to strip the prefix, similar to
how SB_VIRTUAL_FILES.* is used elsewhere, and replace occurrences of
RESOLVED_VIRTUAL_ID in the generated source with that public ID.

- Renamed the `RESOLVED_VIRTUAL_ID` constant to `PROJECT_ANNOTATIONS_VIRTUAL_ID` for clarity.
- Updated import statements in `codegen-modern-iframe-script.ts` to reflect the new naming.
- Adjusted the order of plugin inclusion in `preset.ts` to ensure `storybookProjectAnnotationsPlugin` is added correctly.
- Cleaned up the `storybook-project-annotations-plugin.ts` by reordering the declaration of `VIRTUAL_ID` and `RESOLVED_VIRTUAL_ID` for better readability.
@valentinpalkovic valentinpalkovic force-pushed the valentin/encapsulate-vite-plugins branch from bea9b8d to 2d0adaa Compare February 12, 2026 13:48
@storybook-bot
Copy link
Contributor

Failed to publish canary version of this pull request, triggered by @valentinpalkovic. See the failed workflow run at: https://github.com/storybookjs/storybook/actions/runs/21949475020

- Updated the `entries` property in the `storybookOptimizeDepsPlugin` to allow for both string and array formats, improving flexibility in dependency optimization.
plugins.push({
name: 'storybook:env-plugin',
config(config) {
const envDefines = stringifyProcessEnvs(envs, config.envPrefix);
Copy link
Member

Choose a reason for hiding this comment

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

take an extra look about this on vitest integration

Copy link
Member

@yannbf yannbf left a comment

Choose a reason for hiding this comment

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

LGTM

@storybook-bot
Copy link
Contributor

Failed to publish canary version of this pull request, triggered by @valentinpalkovic. See the failed workflow run at: https://github.com/storybookjs/storybook/actions/runs/22184468133

@valentinpalkovic valentinpalkovic merged commit c84a207 into next Feb 19, 2026
122 of 125 checks passed
@valentinpalkovic valentinpalkovic deleted the valentin/encapsulate-vite-plugins branch February 19, 2026 15:11
@JReinhold JReinhold restored the valentin/encapsulate-vite-plugins branch February 20, 2026 08:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

builder-vite ci:normal maintenance User-facing maintenance tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Maintenance]: Modularize builder-vite into reusable plugins for addon-vitest parity

3 participants