Skip to content

Conversation

@walkerburgin
Copy link
Contributor

@walkerburgin walkerburgin commented Sep 29, 2025

What I did

Updated the storybook:external-globals-plugin Vite plugin to handle the case where pkg.cache('sb-vite-plugin-externals', { create: true }) returns undefined. This can apparently happen when the directory empathic/package finds is not writeable:

/**
* Construct a path to a `node_modules/.cache/<name>` directory.
*
* This may return `undefined` if:
*   1. no "package.json" could be found
*   2. the nearest "node_modules" directory is not writable
*   3. the "node_modules" parent directory is not writable
*
* ...
*/

This causes a hard failure like this:

image

The change proposed in this PR is based on how this is handled in code/core/src/common/utils/resolve-path-in-sb-cache.ts (here).

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

I tested this manually in our repository by patching @storybook/builder-vite. Not sure it's worth the effort to write an automated test, but happy to try if necessary.

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 PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

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

Summary by CodeRabbit

  • Bug Fixes
    • Improved development stability by adding a safe fallback for caching external dependencies, preventing rare crashes when a cache location isn’t available.
    • Ensures smoother startup and runtime during local serve scenarios with more resilient cache handling.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 29, 2025

Walkthrough

The externalGlobalsPlugin in builder-vite updates how it determines cachePath during serve. Instead of asserting a non-null value from pkg.cache(...), it now uses a nullish coalescing fallback to node_modules/.cache/sb-vite-plugin-externals when pkg.cache(...) returns nullish. This change prevents crashes from null cache values and ensures a default cache directory is used. No other control flow or feature behavior is altered.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant Vite as Vite Dev Server
  participant Plugin as externalGlobalsPlugin
  participant Pkg as pkg utils

  Dev->>Vite: start serve
  Vite->>Plugin: initialize plugin
  Plugin->>Pkg: cache("sb-vite-plugin-externals")
  alt cache path available
    Pkg-->>Plugin: return path
    note right of Plugin: Use pkg-provided cachePath
  else cache path nullish
    Pkg-->>Plugin: null/undefined
    Plugin-->>Plugin: fallback to "node_modules/.cache/sb-vite-plugin-externals"
    note right of Plugin: Changed: added safe fallback
  end
  Plugin-->>Vite: proceed with resolved cachePath
Loading

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title Check ✅ Passed The title succinctly identifies the primary change—improving how the external-globals-plugin handles an undefined cache directory—and is directly aligned with the core update described in the PR objectives and code changes. It is clear, specific, and concise without extraneous details, making it easy for reviewers to understand the purpose at a glance.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 0

🧹 Nitpick comments (2)
code/builders/builder-vite/src/plugins/external-globals-plugin.ts (2)

55-57: Good fallback for undefined cache; consider adding a last‑resort tmpdir fallback for unwritable projects

The nullish fallback prevents the hard crash. In locked or non‑writable environments (e.g., some CI or PnP setups), process.cwd()/node_modules/.cache might also be unwritable. Consider a final fallback to os.tmpdir() (namespaced by project path hash) to keep dev server resilient.

Example diff within this block:

-      const cachePath =
-        pkg.cache('sb-vite-plugin-externals', { create: true }) ??
-        join(process.cwd(), 'node_modules', '.cache', 'sb-vite-plugin-externals');
+      const cachePath =
+        pkg.cache('sb-vite-plugin-externals', { create: true }) ??
+        join(process.cwd(), 'node_modules', '.cache', 'sb-vite-plugin-externals');

And outside this block, you could add:

import { tmpdir } from 'node:os';
import crypto from 'node:crypto';

const safeCachePath = (p: string | undefined) =>
  p ?? join(tmpdir(), 'sb-vite-plugin-externals', crypto.createHash('md5').update(process.cwd()).digest('hex'));

Then use safeCachePath(cachePath) where you derive externalCachePath.


60-63: Escape externalKey when building the alias RegExp

Raw package names can contain regex metacharacters (e.g., .). Using them unescaped in new RegExp(\^${externalKey}$`)can lead to accidental over‑matching. You already haveescapeKeys`; reuse it here.

-          newAlias.push({ find: new RegExp(`^${externalKey}$`), replacement: externalCachePath });
+          newAlias.push({ find: new RegExp(`^${escapeKeys(externalKey)}$`), replacement: externalCachePath });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 93afdba and f7e6ce3.

📒 Files selected for processing (1)
  • code/builders/builder-vite/src/plugins/external-globals-plugin.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/builders/builder-vite/src/plugins/external-globals-plugin.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/builders/builder-vite/src/plugins/external-globals-plugin.ts

@ndelangen ndelangen changed the title Fix storybook:external-globals-plugin to handle undefined cache directory Core: Fix external-globals-plugin handle undefined cache dir Sep 30, 2025
@ndelangen ndelangen self-assigned this Sep 30, 2025
@nx-cloud
Copy link

nx-cloud bot commented Sep 30, 2025

View your CI Pipeline Execution ↗ for commit f7e6ce3

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 48s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-30 07:24:44 UTC

@ndelangen ndelangen merged commit 79b35ae into storybookjs:next Sep 30, 2025
58 of 59 checks passed
@github-actions github-actions bot mentioned this pull request Sep 30, 2025
16 tasks
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.

2 participants