Skip to content

Builder-Vite: Fix cold-cache vitest failures for story paths containing glob special characters#34044

Merged
valentinpalkovic merged 2 commits intonextfrom
copilot/fix-vite-addon-cold-cache
Mar 6, 2026
Merged

Builder-Vite: Fix cold-cache vitest failures for story paths containing glob special characters#34044
valentinpalkovic merged 2 commits intonextfrom
copilot/fix-vite-addon-cold-cache

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 6, 2026

When story files live inside directories with parentheses (e.g. Next.js route group dirs like src/(group)/...), the first cold-cache run fails because optimizeDeps.entries paths are passed raw to Vite, which processes them via fast-glob — interpreting (group) as an extglob pattern rather than a literal path segment. This causes the story file to be missed during the initial dep scan, triggering a runtime re-optimization and the "Vite unexpectedly reloaded a test" failure.

Manual testing instructions:

Changes

  • storybook-optimize-deps-plugin.ts: Added escapeGlobPath() that backslash-escapes glob special characters (()[]{}!*?|+@) in file paths. Applied to both story import paths and preview annotation paths before they're spread into optimizeDeps.entries.
// Before: parentheses pass through unescaped → fast-glob misinterprets as extglob
entries: [...getUniqueImportPaths(index), ...previewAnnotationEntries]

// After: paths are escaped so they're treated as literals
entries: [...getUniqueImportPaths(index).map(escapeGlobPath), ...previewAnnotationEntries.map(escapeGlobPath)]

// escapeGlobPath('src/(group)/Button.stories.tsx')
// → 'src/\\(group\\)/Button.stories.tsx'
  • storybook-optimize-deps-plugin.test.ts: New test file covering escapeGlobPath for parentheses, brackets, braces, wildcards, and plain paths.
Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug]: addon-vitest first cold-cache run fails when story path contains parentheses (e.g. src/(group))</issue_title>
<issue_description>### Describe the bug

When running Storybook tests with @storybook/addon-vitest, the first run after clearing cache fails if the story file is inside a parenthesized directory (for example src/(group)/...).

Behavior:

  • Cold cache (rm -rf node_modules/.cache) + first pnpm test-storybook run fails.
  • Second run (without clearing cache) passes.
  • If I add this workaround, first cold-cache run passes:
viteFinal: async (config) => {
  config.optimizeDeps = {
    ...config.optimizeDeps,
    entries: ["src/**/*.stories.@(js|jsx|ts|tsx)"],
  };
  return config;
},
  • Also, if I rename src/(group) to src/group (same story code), first cold-cache run passes.

Error on failing run includes:

  • new dependencies optimized: @radix-ui/react-accordion
  • optimized dependencies changed. reloading
  • Vite unexpectedly reloaded a test
  • Failed to fetch dynamically imported module: .../node_modules/.cache/storybook/.../sb-vitest/deps/...

Reproduction link

https://github.com/hwld/storybook-vite-vitest-cold-cache-repro

Reproduction steps

  1. git clone https://github.com/hwld/storybook-vite-vitest-cold-cache-repro.git
  2. cd storybook-vite-vitest-cold-cache-repro
  3. pnpm install
  4. git checkout main
  5. rm -rf node_modules/.cache
  6. pnpm test-storybook -> fails on first run
  7. pnpm test-storybook again -> passes

Workaround confirmation:

  1. git checkout workaround
  2. rm -rf node_modules/.cache
  3. pnpm test-storybook -> passes on first run

System

System:
  OS: macOS 15.3 (Darwin 25.3.0) arm64
Binaries:
  Node: v22.16.0
  pnpm: 10.12.1
npmPackages:
  storybook: 10.3.0-alpha.14
  @storybook/addon-vitest: 10.3.0-alpha.14
  @storybook/nextjs-vite: 10.3.0-alpha.14
  vite: 7.2.1
  vitest: 4.0.18
  next: 15.3.3
  react: 19.2.4

Additional context

This looks related to dependency optimization entry handling for story paths with parentheses.

My understanding:

  • Storybook builder-vite passes story importPath values into optimizeDeps.entries.
  • Vite treats optimizeDeps.entries as glob patterns.
  • Parentheses in path segments ((group)) are treated as dynamic pattern syntax, so the literal story path may not be matched in initial scan.
  • Then dependency optimization happens later during runtime, causing reload and the first-run failure.

Possibly related (not identical):

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Summary by CodeRabbit

Release Notes

  • New Features

    • Improved handling of file paths containing special characters (parentheses, brackets, glob patterns) during Vite optimization to prevent unintended character interpretation.
  • Tests

    • Added comprehensive test suite covering various special character escaping scenarios.

…t cold-cache failures

Co-authored-by: valentinpalkovic <5889929+valentinpalkovic@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix bug in addon-vitest cold-cache run with story path Fix cold-cache vitest failures for story paths containing glob special characters (e.g. Next.js route groups) Mar 6, 2026
@valentinpalkovic valentinpalkovic changed the title Fix cold-cache vitest failures for story paths containing glob special characters (e.g. Next.js route groups) Builder-Vite: Fix cold-cache vitest failures for story paths containing glob special characters Mar 6, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 6, 2026

Fails
🚫 PR description is missing the mandatory "#### Manual testing" section. Please add it so that reviewers know how to manually test your changes.

Generated by 🚫 dangerJS against 5aac90b

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Mar 6, 2026

View your CI Pipeline Execution ↗ for commit 5aac90b

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

☁️ Nx Cloud last updated this comment at 2026-03-06 12:25:02 UTC

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

A new utility function escapeGlobPath is introduced to escape special glob characters in file paths, preventing unintended glob pattern interpretation by Vite's dependency optimizer. The function is integrated into the storybookOptimizeDepsPlugin and accompanied by a comprehensive test suite.

Changes

Cohort / File(s) Summary
Core Implementation
code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.ts
Adds escapeGlobPath utility function to escape special glob characters (parentheses, brackets, braces, wildcards). Integrates the function into dep optimization entries for index imports and preview annotations.
Test Suite
code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.test.ts
Comprehensive Vitest tests for escapeGlobPath covering plain paths, individual special characters, glob characters, combinations, and unchanged paths.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)

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

Copy link
Copy Markdown
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.

🧹 Nitpick comments (2)
code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.test.ts (2)

28-31: Consider adding test coverage for remaining escaped characters.

The escapeGlobPath regex escapes !, |, +, and @ in addition to the characters currently tested. While these are less common in file paths, adding coverage would ensure the implementation is fully verified.

Example additions:

it('should escape extglob prefix characters', () => {
  expect(escapeGlobPath('./src/!important/file.ts')).toBe('./src/\\!important/file.ts');
  expect(escapeGlobPath('./src/a+b/file.ts')).toBe('./src/a\\+b/file.ts');
  expect(escapeGlobPath('./src/@scope/file.ts')).toBe('./src/\\@scope/file.ts');
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.test.ts`
around lines 28 - 31, Add tests to cover the remaining characters escaped by
escapeGlobPath (specifically '!', '|', '+', and '@'): update
storybook-optimize-deps-plugin.test.ts to include a new it block (or extend the
existing cases) that calls escapeGlobPath with paths containing each of these
characters and asserts they are escaped with a backslash (e.g.
'./src/!important/file.ts' -> './src/\\!important/file.ts', './src/a+b/file.ts'
-> './src/a\\+b/file.ts', './src/@scope/file.ts' -> './src/\\@scope/file.ts',
and a case for '|' similarly). Ensure the test references the escapeGlobPath
function and uses expect(...).toBe(...) for each input/expected pair so the
regex coverage is validated.

39-43: Redundant test case.

This test is functionally identical to the first test case on lines 6-8. Both verify that paths without special glob characters remain unchanged. Consider removing one or differentiating them (e.g., test with different path structures like absolute paths or paths with hyphens/underscores).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.test.ts`
around lines 39 - 43, Remove or modify the redundant test with description
"should not modify paths that contain no special glob characters" which
duplicates the earlier test that asserts unchanged behavior for simple paths;
either delete this second it(...) block or change it to cover a different case
(e.g., use an absolute path, different separators, or names with
hyphens/underscores) so the test
`escapeGlobPath('./src/my-component/Button.stories.tsx')` provides unique
coverage compared to the first test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.test.ts`:
- Around line 28-31: Add tests to cover the remaining characters escaped by
escapeGlobPath (specifically '!', '|', '+', and '@'): update
storybook-optimize-deps-plugin.test.ts to include a new it block (or extend the
existing cases) that calls escapeGlobPath with paths containing each of these
characters and asserts they are escaped with a backslash (e.g.
'./src/!important/file.ts' -> './src/\\!important/file.ts', './src/a+b/file.ts'
-> './src/a\\+b/file.ts', './src/@scope/file.ts' -> './src/\\@scope/file.ts',
and a case for '|' similarly). Ensure the test references the escapeGlobPath
function and uses expect(...).toBe(...) for each input/expected pair so the
regex coverage is validated.
- Around line 39-43: Remove or modify the redundant test with description
"should not modify paths that contain no special glob characters" which
duplicates the earlier test that asserts unchanged behavior for simple paths;
either delete this second it(...) block or change it to cover a different case
(e.g., use an absolute path, different separators, or names with
hyphens/underscores) so the test
`escapeGlobPath('./src/my-component/Button.stories.tsx')` provides unique
coverage compared to the first test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1f2eef27-eeb3-4218-8630-ae950bbccb0f

📥 Commits

Reviewing files that changed from the base of the PR and between e81fd16 and 5aac90b.

📒 Files selected for processing (2)
  • code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.test.ts
  • code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.ts

@valentinpalkovic valentinpalkovic merged commit b0d8dd4 into next Mar 6, 2026
125 of 139 checks passed
@valentinpalkovic valentinpalkovic deleted the copilot/fix-vite-addon-cold-cache branch March 6, 2026 13:19
@valentinpalkovic valentinpalkovic added the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Mar 10, 2026
@Sidnioulz Sidnioulz removed the needs qa Indicates that this needs manual QA during the upcoming minor/major release label Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: addon-vitest first cold-cache run fails when story path contains parentheses (e.g. src/(group))

3 participants