Skip to content

Conversation

@akornmeier
Copy link
Contributor

@akornmeier akornmeier commented Dec 4, 2025

What I did

When using vite-rolldown, bundled code creates different object references for the same module imported from multiple files. This caused Map.get() lookups to fail since Maps use object identity.

  • Add fallback lookup by .default property in resolveModuleExport()
  • Handles bundlers that don't preserve ES module namespace identity
  • Add tests for Rolldown compatibility scenarios

Closes #31879

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

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

Manual testing

Cloned the repro repo posted in the GitHub issue: https://github.com/beaussan/repro-storybook-rolldown-story-of

  • Installed Storybook from my local tarball created after the update
  • Reinstalled dependencies, built project, ran Storybook, confirmed fix validity (tarball attached to this comment)

Documentation

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

Checklist for Maintainers

storybook-10.2.0-alpha.3.tgz

  • 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 publish.yml --field pr=<PR_NUMBER>

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced compatibility with bundlers that don't preserve module namespace identity (e.g., Rolldown) by improving module export resolution, ensuring correct default export handling.
  • Tests

    • Added comprehensive tests to verify proper reference and module resolution in bundler compatibility scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

When using vite-rolldown, bundled code creates different object
references for the same module imported from multiple files. This caused
Map.get() lookups to fail since Maps use object identity.

- Add fallback lookup by .default property in resolveModuleExport() -
Handles bundlers that don't preserve ES module namespace identity - Add
tests for Rolldown compatibility scenarios

Fixes storybookjs#31879
Copilot AI review requested due to automatic review settings December 4, 2025 13:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an issue where the Rolldown bundler creates different object references for the same module imported from multiple files, causing Map.get() lookups to fail. The solution adds a fallback lookup mechanism that checks the .default property when direct lookup fails, maintaining compatibility with bundlers that don't preserve ES module namespace object identity.

Key changes:

  • Add fallback lookup in resolveModuleExport() method to check .default property when direct Map lookup fails
  • Add comprehensive unit tests for Rolldown compatibility scenarios

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts Implements fallback lookup logic in resolveModuleExport() to handle bundlers like Rolldown that create different namespace object references
code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts Adds unit tests for Rolldown compatibility in both referenceMeta and resolveOf test suites, plus a test for error handling with non-module objects

- Align expected error message in referenceMeta test with the more
helpful message in DocsContext that suggests the user may have
mistakenly referenced their component instead of their CSF file
@valentinpalkovic valentinpalkovic added bug patch:yes Bugfix & documentation PR that need to be picked to main branch addon: docs ci:normal block: other labels Dec 5, 2025
@valentinpalkovic valentinpalkovic changed the title fix(docs): support Rolldown bundler module namespace objects Docs: Support Rolldown bundler module namespace objects Dec 5, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds a fallback resolution mechanism in DocsContext to handle bundlers like Rolldown that don't preserve module namespace identity. When direct lookup fails and the object contains a .default property, the code now attempts resolution using that default export. Corresponding tests verify this compatibility path.

Changes

Cohort / File(s) Change Summary
Module resolution fallback
code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts
Introduces fallback lookup mechanism: when direct module export lookup fails, checks if the input object has a .default property and attempts resolution using that instead. Handles bundlers with inconsistent module namespace identity.
Rolldown compatibility tests
code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
Adds tests for referenceMeta and resolveOf to verify handling of Rolldown-style module objects with shared .default exports, and validates error handling for non-module objects passed to referenceMeta.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Fallback logic verification: Confirm the fallback mechanism triggers only when appropriate and doesn't mask legitimate resolution failures
  • Test coverage: Verify tests cover both success and failure paths for Rolldown-style modules and non-module object rejection
  • Edge cases: Check handling of objects that have a .default property but should not use the fallback path
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bd55eb and baf7766.

📒 Files selected for processing (2)
  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts (2 hunks)
  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{test,spec}.{ts,tsx}: Test files should follow the naming pattern *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx
Follow the spy mocking rules defined in .cursor/rules/spy-mocking.mdc for consistent mocking patterns with Vitest

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access the mocked functions in Vitest tests
Implement mock behaviors in beforeEach blocks in Vitest tests
Mock all required dependencies that the test subject uses
Each mock implementation should return a Promise for async functions in Vitest
Mock implementations should match the expected return type of the original function
Mock all required properties and methods that the test subject uses in Vitest tests
Avoid direct function mocking without vi.mocked() in Vitest tests
Avoid mock implementations outside of beforeEach blocks in Vitest tests
Avoid mocking without the spy: true option in Vitest tests
Avoid inline mock implementations within test cases in Vitest tests
Avoid mocking only a subset of required dependencies in Vitest tests
Mock at the highest level of abstraction needed in Vitest tests
Keep mock implementations simple and focused in Vitest tests
Use type-safe mocking with vi.mocked() in Vitest tests
Document complex mock behaviors in Vitest tests
Group related mocks together in Vitest tests

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

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

Use ESLint and Prettier configurations that are enforced in the codebase

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts
**/*.{ts,tsx}

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

Enable TypeScript strict mode

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts
code/**/*.{ts,tsx,js,jsx,mjs}

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

code/**/*.{ts,tsx,js,jsx,mjs}: Use server-side logger from 'storybook/internal/node-logger' for Node.js code
Use client-side logger from 'storybook/internal/client-logger' for browser code
Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts
code/**/*.{ts,tsx,js,jsx}

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

Export functions that need to be tested from their modules

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts
code/**/*.{test,spec}.{ts,tsx,js,jsx}

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

code/**/*.{test,spec}.{ts,tsx,js,jsx}: Write meaningful unit tests that actually import and call the functions being tested
Mock external dependencies using vi.mock() for file system, loggers, and other external dependencies in tests
Aim for high test coverage of business logic (75%+ for statements/lines) using coverage reports

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
code/**/*.{js,jsx,json,html,ts,tsx,mjs}

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

code/**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier with --write flag to format code before committing
Run ESLint with yarn lint:js:cmd to check for linting issues and fix errors before committing

Files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts
🧠 Learnings (3)
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
📚 Learning: 2025-11-24T17:49:59.279Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-11-24T17:49:59.279Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies in Vitest tests

Applied to files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
📚 Learning: 2025-11-28T14:50:24.889Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-28T14:50:24.889Z
Learning: Applies to code/**/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested

Applied to files:

  • code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts
🧬 Code graph analysis (1)
code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts (1)
code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts (1)
  • DocsContext (20-281)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: normal
🔇 Additional comments (3)
code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts (2)

83-115: Nice coverage for Rolldown namespace behavior and error-path validation

The referenceMeta tests do a good job of:

  • Accurately simulating Rolldown’s behavior by creating a new namespace object that shares the same .default meta export, and
  • Verifying the happy-path (no throw, primary story wired) and the error-path for passing a component, with the full error message matching the implementation.

This directly exercises the new fallback and guards against regressions in the user-facing error.


150-158: resolveOf Rolldown test correctly exercises the new fallback path

The added resolveOf test with a “different module exports but same default” object cleanly validates that:

  • The fallback via .default is used when namespace identity differs, and
  • The result still resolves as type: 'meta' with preparedMeta present, preserving existing semantics.

This complements the referenceMeta test and gives good confidence the new behavior is consistent across both resolution entry points. Based on learnings, this is a meaningful unit test that directly calls the code under test.

code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts (1)

160-172: Fallback via .default cleanly handles Rolldown without regressing existing behavior

The new logic:

  • First attempts the existing exportsToCSFFile lookup.
  • On miss, conditionally falls back to moduleExportOrType.default only when the value is a non-null object with a default property.
  • Reuses the existing exportsToCSFFile mapping keyed by the meta export, so it correctly leverages the shared identity of the default export while tolerating differing namespace objects.

This keeps the fast path unchanged, avoids touching story/component resolution, and is well-guarded against primitives or typical component functions (no .default). The change is minimal, targeted, and aligns with the new tests.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@valentinpalkovic valentinpalkovic merged commit e0d0d04 into storybookjs:next Dec 9, 2025
58 of 63 checks passed
valentinpalkovic added a commit that referenced this pull request Dec 9, 2025
Docs: Support Rolldown bundler module namespace objects
(cherry picked from commit e0d0d04)
@github-actions github-actions bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Dec 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

addon: docs block: other bug ci:normal patch:done Patch/release PRs already cherry-picked to main/release branch patch:yes Bugfix & documentation PR that need to be picked to main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Storybook built with vite-rolldown throws when using <Meta of>

2 participants