Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 22, 2025

What I did

Extends the manifest generation system to include MDX documentation files alongside component manifests. This enables AI agents and other tools to access structured documentation content through the manifest API.

Key Changes

addon-docs (code/addons/docs/src/manifest.ts)

  • New experimental_manifests preset function that processes MDX docs entries
  • Attached MDX entries (attached-mdx tag) are added to their corresponding component manifests under a docs property
  • Unattached MDX entries (unattached-mdx tag) are added to a separate /manifests/docs.json endpoint
  • Includes the raw MDX content for each docs entry

React renderer (code/renderers/react/src/componentManifest/generator.ts)

  • Updated to create component manifests even when only attached-mdx docs entries have the manifest tag (previously required story entries)
  • Uses storiesImports[0] to find the story file for attached docs entries

Core server (code/core/src/core-server/utils/manifests/manifests.ts)

  • Updated to properly handle the new docs manifest format

Manifest Structure

Attached docs are added to component manifests:

{
  "components": {
    "v": 0,
    "components": {
      "example-button": {
        "id": "example-button",
        "name": "Button",
        "docs": {
          "example-button--docs": {
            "id": "example-button--docs",
            "name": "docs",
            "path": "./Button.mdx",
            "title": "Example/Button",
            "content": "# Button\n\nDocumentation content..."
          }
        }
      }
    }
  }
}

Unattached docs are served at /manifests/docs.json:

{
  "v": 0,
  "docs": {
    "standalone--docs": {
      "id": "standalone--docs",
      "name": "docs",
      "path": "./Standalone.mdx",
      "title": "Standalone",
      "content": "# Standalone\n\nStandalone documentation..."
    }
  }
}

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

  1. Run a sandbox: yarn task --task sandbox --start-from auto --template react-vite/default-ts
  2. Add an MDX file and use <Meta of={ButtonStories} /> to attach it to the Button stories.
  3. Start Storybook and access /manifests/components.json to see attached docs in component entries
  4. Access /manifests/docs.json to see unattached docs entries

Documentation

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

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a documentation manifest system for organizing and managing documentation entries alongside component manifests.
    • Added support for both standalone and component-attached documentation entries with automatic content extraction.
    • Enhanced component manifests to include documentation metadata and file handling.
  • Tests

    • Added comprehensive test coverage for docs manifest handling and error scenarios.
    • Added test coverage for component manifest generation with documentation entries.

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

Copilot AI self-assigned this Dec 22, 2025
Copilot AI and others added 3 commits December 22, 2025 10:49
- Create manifest.ts to generate manifests for MDX files
- Filter MDX entries with 'attached-mdx' or 'unattached-mdx' tags
- Export experimental_manifests from preset.ts
- Add comprehensive tests for MDX manifest generation

Co-authored-by: JReinhold <[email protected]>
Copilot AI changed the title [WIP] Add support for MDX files in manifest generation feat(addon-docs): add MDX manifest generation Dec 22, 2025
Copilot AI requested a review from JReinhold December 22, 2025 10:55
Base automatically changed from jeppe/support-manifest-tag-in-preview to next December 22, 2025 22:04
@nx-cloud
Copy link

nx-cloud bot commented Dec 22, 2025

View your CI Pipeline Execution ↗ for commit d91d75c

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ✅ Succeeded 9m 32s View ↗

☁️ Nx Cloud last updated this comment at 2025-12-29 09:43:56 UTC

@JReinhold JReinhold changed the title feat(addon-docs): add MDX manifest generation Manifest: Add basic support for attached and unattached MDX Dec 29, 2025
@JReinhold JReinhold added react addon: docs ci:normal manifest Component manifest generation labels Dec 29, 2025
@storybook-app-bot
Copy link

storybook-app-bot bot commented Dec 29, 2025

Package Benchmarks

Commit: d91d75c, ran on 29 December 2025 at 09:42:57 UTC

No significant changes detected, all good. 👏

@JReinhold JReinhold changed the title Manifest: Add basic support for attached and unattached MDX Addon-docs: Add MDX manifest generation Dec 29, 2025
@JReinhold JReinhold marked this pull request as ready for review December 29, 2025 09:32
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

📝 Walkthrough

Walkthrough

Introduces a Docs manifest system for Storybook that processes DocsIndexEntry entries into structured manifests. Supports both attached MDX entries integrated into component manifests and unattached (standalone) MDX entries in a separate docs manifest. Extends the experimental_manifests preset with filtering, grouping, and content extraction logic. Updates the component manifest generator to recognize and process attached MDX docs entries with dynamic path resolution.

Changes

Cohort / File(s) Summary
Docs Manifest System
code/addons/docs/src/manifest.ts, code/addons/docs/src/manifest.test.ts
Introduces DocsManifestEntry and related types; adds createDocsManifestEntry, extractUnattachedDocsEntries, and extractAttachedDocsEntries helper functions; extends experimental_manifests preset to filter docs entries, group them by tag (attached-mdx/unattached-mdx), generate manifests concurrently, and attach docs to component manifests or global docs namespace. Comprehensive test suite covers attached/unattached entries, error handling (ENOENT), content extraction, and mixed scenarios.
Preset Export
code/addons/docs/src/preset.ts
Re-exports manifests as experimental_manifests; removes unused CsfEnricher import.
Component Manifest Generator
code/renderers/react/src/componentManifest/generator.ts, code/renderers/react/src/componentManifest/generator.test.ts
Extends manifest filtering to recognize attached-mdx docs entries; introduces storyFilePath resolution logic to derive component path from either story importPath or attached docs storiesImports; updates component manifest path field to use resolved storyFilePath. New test validates manifest generation when docs entry carries manifest tag.

Sequence Diagram(s)

sequenceDiagram
    participant Config as Manifest Processor
    participant Filter as Entry Grouper
    participant Attached as Attached Handler
    participant Unattached as Unattached Handler
    participant Output as Manifest Builder

    Config->>Filter: docs entries (filtered by type)
    Filter->>Filter: separate by tag:<br/>attached-mdx / unattached-mdx / ignored
    
    rect rgb(200, 220, 255)
    Note over Attached,Unattached: Concurrent Processing
    Filter->>Attached: attached-mdx entries +<br/>existing components
    Filter->>Unattached: unattached-mdx entries
    
    Attached->>Attached: attach docs to<br/>component manifests
    Unattached->>Unattached: extract content from MDX,<br/>handle errors
    end
    
    Attached-->>Output: updated components manifest
    Unattached-->>Output: docs manifest with<br/>DocsManifestEntries
    Output->>Output: merge into final<br/>ManifestsWithDocs
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

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/addons/docs/src/manifest.ts (2)

92-116: Consider a non-mutating approach for extractAttachedDocsEntries.

This function mutates existingComponents directly (lines 108-111). While it works correctly and the caller handles the result appropriately, a non-mutating approach would be more predictable and align with functional programming best practices.

🔎 Proposed non-mutating approach
 export async function extractAttachedDocsEntries(
   entries: DocsIndexEntry[],
   existingComponents: ComponentsManifestWithDocs | undefined
 ): Promise<ComponentsManifestWithDocs | undefined> {
   if (!existingComponents || entries.length === 0) {
     return existingComponents;
   }

   const entriesWithContent = await Promise.all(entries.map(createDocsManifestEntry));

+  // Build updated components without mutating
+  const updatedComponents = { ...existingComponents.components };
+
   // Add docs to their corresponding components based on the entry id prefix
   for (const docsEntry of entriesWithContent) {
     const componentId = docsEntry.id.split('--')[0];

-    const component = existingComponents.components[componentId];
+    const component = updatedComponents[componentId];
     if (component) {
-      if (!component.docs) {
-        component.docs = {};
-      }
-      component.docs[docsEntry.id] = docsEntry;
+      updatedComponents[componentId] = {
+        ...component,
+        docs: {
+          ...component.docs,
+          [docsEntry.id]: docsEntry,
+        },
+      };
     }
   }

-  return existingComponents;
+  return {
+    ...existingComponents,
+    components: updatedComponents,
+  };
 }

16-17: These constants are duplicated across the codebase.

The same ATTACHED_MDX_TAG and UNATTACHED_MDX_TAG constants are already exported from code/core/src/core-server/utils/StoryIndexGenerator.ts (and also from code/core/src/preview-api/modules/preview-web/PreviewWithSelection.tsx). However, they are not currently exposed through the storybook/internal/* public API, and importing from those internal core-server modules would require a cross-package import. Consider whether extracting these to a shared storybook/internal/* export location would be worthwhile to eliminate duplication.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d036b5 and d91d75c.

📒 Files selected for processing (5)
  • code/addons/docs/src/manifest.test.ts
  • code/addons/docs/src/manifest.ts
  • code/addons/docs/src/preset.ts
  • code/renderers/react/src/componentManifest/generator.test.ts
  • code/renderers/react/src/componentManifest/generator.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{js,jsx,ts,tsx,json,md,html,css,scss}

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

Format code using Prettier with yarn prettier --write <file>

Files:

  • code/addons/docs/src/manifest.ts
  • code/addons/docs/src/preset.ts
  • code/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.ts
  • code/renderers/react/src/componentManifest/generator.test.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

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

Run ESLint checks using yarn lint:js:cmd <file> or the full command cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives to fix linting errors before committing

Files:

  • code/addons/docs/src/manifest.ts
  • code/addons/docs/src/preset.ts
  • code/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.ts
  • code/renderers/react/src/componentManifest/generator.test.ts
**/*.{ts,tsx}

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

Enable TypeScript strict mode across all packages

Files:

  • code/addons/docs/src/manifest.ts
  • code/addons/docs/src/preset.ts
  • code/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.ts
  • code/renderers/react/src/componentManifest/generator.test.ts
**/*.{ts,tsx,js,jsx}

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

**/*.{ts,tsx,js,jsx}: Export functions from modules if they need to be tested
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/addons/docs/src/manifest.ts
  • code/addons/docs/src/preset.ts
  • code/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.ts
  • code/renderers/react/src/componentManifest/generator.test.ts
code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx}

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

Use logger from storybook/internal/node-logger for server-side logging in Node.js code

Files:

  • code/addons/docs/src/manifest.ts
  • code/addons/docs/src/preset.ts
  • code/addons/docs/src/manifest.test.ts
**/*.{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/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.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/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

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

**/*.{test,spec}.{ts,tsx,js,jsx}: Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns
Achieve high test coverage of business logic, aiming for 75%+ coverage of statements/lines
Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests
Use vi.mock() to mock file system, loggers, and other external dependencies in tests

Files:

  • code/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.test.ts
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to {code/addons,code/frameworks}/**/README.md : Update README files for significant changes and include code examples in addon/framework documentation
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to {code/addons,code/frameworks}/**/README.md : Update README files for significant changes and include code examples in addon/framework documentation

Applied to files:

  • code/addons/docs/src/manifest.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{core,lib,addons,builders,frameworks,presets}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/node-logger` for server-side logging in Node.js code

Applied to files:

  • code/addons/docs/src/preset.ts
  • code/renderers/react/src/componentManifest/generator.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to code/{renderers}/**/*.{ts,tsx,js,jsx} : Use `logger` from `storybook/internal/client-logger` for client-side logging in browser code

Applied to files:

  • code/addons/docs/src/preset.ts
  • code/renderers/react/src/componentManifest/generator.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Cover all branches, conditions, edge cases, error paths, and different input variations in unit tests

Applied to files:

  • code/addons/docs/src/manifest.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write meaningful unit tests that actually import and call the functions being tested, not just verify syntax patterns

Applied to files:

  • code/addons/docs/src/manifest.test.ts
  • code/renderers/react/src/componentManifest/generator.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} : Document complex mock behaviors in Vitest tests

Applied to files:

  • code/addons/docs/src/manifest.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/addons/docs/src/manifest.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 inline mock implementations within test cases in Vitest tests

Applied to files:

  • code/addons/docs/src/manifest.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} : Keep mock implementations simple and focused in Vitest tests

Applied to files:

  • code/addons/docs/src/manifest.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 mock implementations outside of `beforeEach` blocks in Vitest tests

Applied to files:

  • code/addons/docs/src/manifest.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} : Each mock implementation should return a Promise for async functions in Vitest

Applied to files:

  • code/addons/docs/src/manifest.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} : Implement mock behaviors in `beforeEach` blocks in Vitest tests

Applied to files:

  • code/addons/docs/src/manifest.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} : Group related mocks together in Vitest tests

Applied to files:

  • code/addons/docs/src/manifest.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} : Mock all required properties and methods that the test subject uses in Vitest tests

Applied to files:

  • code/addons/docs/src/manifest.test.ts
📚 Learning: 2025-12-22T22:03:40.123Z
Learnt from: CR
Repo: storybookjs/storybook PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T22:03:40.123Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Use `vi.mock()` to mock file system, loggers, and other external dependencies in tests

Applied to files:

  • code/addons/docs/src/manifest.test.ts
📚 Learning: 2025-10-01T15:24:01.060Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32594
File: code/core/src/components/components/Popover/WithPopover.tsx:7-9
Timestamp: 2025-10-01T15:24:01.060Z
Learning: In the Storybook repository, "react-aria-components/patched-dist/*" (e.g., "react-aria-components/patched-dist/Dialog", "react-aria-components/patched-dist/Popover", "react-aria-components/patched-dist/Tooltip") are valid import paths created by a patch applied to the react-aria-components package. These imports should not be flagged as broken or invalid until a maintainer explicitly states they are no longer acceptable.

Applied to files:

  • code/renderers/react/src/componentManifest/generator.ts
📚 Learning: 2025-11-05T09:38:47.712Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/Select/Select.tsx:200-204
Timestamp: 2025-11-05T09:38:47.712Z
Learning: Repo: storybookjs/storybook — Guidance: Until Storybook 11 is released, do not suggest using React.useId anywhere (e.g., in code/core/src/components/components/Select/Select.tsx) to maintain compatibility with React 17 runtimes. Prefer advising: accept a caller-provided props.id and, if needed, generate a client-only fallback id to minimize SSR hydration issues — but avoid useId. Resume prompting for useId after Storybook 11.

Applied to files:

  • code/renderers/react/src/componentManifest/generator.ts
📚 Learning: 2025-11-05T09:37:25.920Z
Learnt from: Sidnioulz
Repo: storybookjs/storybook PR: 32458
File: code/core/src/components/components/tooltip/WithTooltip.tsx:54-96
Timestamp: 2025-11-05T09:37:25.920Z
Learning: Repo: storybookjs/storybook — In code/core/src/components/components/tooltip/WithTooltip.tsx, the legacy WithTooltip implementation is intentionally reintroduced for backward compatibility and is deprecated; maintainers (per Sidnioulz) do not want maintenance or improvements on it. Prefer WithTooltipNew/Popover; avoid suggesting changes to WithTooltip.* going forward.

Applied to files:

  • code/renderers/react/src/componentManifest/generator.ts
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
Repo: storybookjs/storybook PR: 32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/renderers/react/src/componentManifest/generator.ts
🧬 Code graph analysis (2)
code/addons/docs/src/manifest.ts (1)
code/core/src/core-server/utils/StoryIndexGenerator.ts (2)
  • ATTACHED_MDX_TAG (68-68)
  • UNATTACHED_MDX_TAG (69-69)
code/renderers/react/src/componentManifest/generator.ts (1)
code/core/src/core-server/utils/StoryIndexGenerator.ts (1)
  • ATTACHED_MDX_TAG (68-68)
⏰ 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). (3)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
  • GitHub Check: nx
🔇 Additional comments (9)
code/addons/docs/src/preset.ts (1)

221-221: LGTM!

Clean re-export that exposes the new docs manifest functionality through the preset system. The experimental_ prefix appropriately signals the API's maturity level.

code/renderers/react/src/componentManifest/generator.test.ts (1)

461-565: LGTM!

Well-structured test that verifies component manifest generation when only attached-mdx docs entries have the manifest tag. The test:

  • Follows existing test patterns in the file
  • Clearly documents the scenario being tested via comments
  • Properly sets up the docs entry with required fields (storiesImports, attached-mdx tag)
  • Validates the expected manifest structure via snapshot
code/renderers/react/src/componentManifest/generator.ts (3)

110-118: LGTM!

The filter logic correctly extends manifest generation to include attached docs entries. The conditions properly guard against accessing storiesImports when it's empty.


124-129: LGTM!

The storyFilePath derivation correctly handles both entry types:

  • Stories use their importPath directly
  • Attached docs use storiesImports[0] to locate the associated story file

This ensures the component manifest is built from the correct source file in both cases.


20-21: The suggestion to import ATTACHED_MDX_TAG from a shared location is not feasible. The constant is not exported through any public API (storybook/internal or otherwise), and the react renderer is intentionally kept separate from core-server. The local duplication is the correct approach for maintaining package boundaries.

Likely an incorrect or invalid review comment.

code/addons/docs/src/manifest.test.ts (2)

10-13: Mock setup note.

The mock pattern here doesn't use the spy: true option mentioned in the coding guidelines. However, since this is mocking the entire node:fs/promises module with memfs (not spying on individual functions), this approach is appropriate for this use case.


50-360: Excellent test coverage!

The test suite thoroughly covers the docs manifest functionality:

  • ✅ No docs entries scenario
  • ✅ Filtering out docs without proper tags
  • ✅ Attached docs integration with component manifests
  • ✅ Unattached docs in separate manifest
  • ✅ Mixed attached/unattached handling
  • ✅ Preservation of existing manifests
  • ✅ Error handling for file read failures
  • ✅ Mixed success/error scenarios

All tests follow the pattern of actually calling the manifests function and asserting on the results. Good job covering edge cases and error paths per the coding guidelines.

code/addons/docs/src/manifest.ts (2)

47-71: LGTM!

The createDocsManifestEntry function properly:

  • Resolves paths relative to cwd
  • Reads file content asynchronously
  • Handles errors gracefully by returning a structured error object instead of throwing

This allows partial success when processing multiple docs entries.


127-185: Well-structured manifest orchestration.

The main manifests function:

  • Early returns for empty inputs (good performance optimization)
  • Uses groupBy for clean categorization with explicit handling of ignored entries
  • Processes attached and unattached docs in parallel via Promise.all
  • Includes verbose performance logging
  • Properly spreads existing manifests to avoid mutation at the top level


/** Converts a DocsIndexEntry to a DocsManifestEntry by reading its file content. */
export async function createDocsManifestEntry(entry: DocsIndexEntry): Promise<DocsManifestEntry> {
const absolutePath = path.join(process.cwd(), entry.importPath);
Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed, evaluating the absolute path of the import path needs a helper function and refactoring, because it's opaque to know what the "workingDir" actually is. I have agreed with Jeppe that refactoring and adjusting other code places as well will be a separate task, likely implemented in the next cooldown cycle.


// Add docs to their corresponding components based on the entry id prefix
for (const docsEntry of entriesWithContent) {
const componentId = docsEntry.id.split('--')[0];
Copy link
Contributor

@valentinpalkovic valentinpalkovic Dec 29, 2025

Choose a reason for hiding this comment

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

We should use a helper function to get the component id. Does storybook/internal/csf already provide a proper helper function?

import { type DocObj } from './reactDocgen';
import { cachedFindUp, cachedReadFileSync, invalidateCache, invariant } from './utils';

const ATTACHED_MDX_TAG = 'attached-mdx';
Copy link
Contributor

Choose a reason for hiding this comment

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

We should export the tag const from core and re-use it in addon/docs and react

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.

3 participants