Repository: storybook
Issue: [Bug]: `pnpm` + `vite` Mono-Repository Test Rig — Cases of No JSDocs, No new file HMR, Recursion, Breaking
Labels: bug,monorepos,argtypes,sev:S2

_Edit 2023-03-18: Consolidated the scope of this ticket to issue cases. See the original at the end._

### Describe the bug

The following provides a list of issue cases of using `storybook` with `pnpm` and `vite`. To do so, I have looked at a number of closed source small to mid scale integrated mono-repository architectures to highlight storybook functionality issues as with as minimal content as possible. I hope this test rig helps you to achieve a "[just work 🤺](https://youtu.be/P0hJm5v8TJw?t=1980)" state within larger projects, as it would help me to integrate storybook / chromatic into such.

In this first version I've only concentrated on sourcing and rendering of stories files. In the future, building, interactions like testing and reporting should probably also be checked. As well as automated via playwright and github actions.

Storybook Version: `^7.0.0-rc.4`
PNPM Version: `^7.29.3`
Node Version: `18 LTS`
Builder: `vite`
Renderer: `react 18`

## Test Rig: Storybook in a Typical PNPM Monorepo

This repository mimics a typical integrated monorepo architecture where individual views or "micro front-ends" consume one or more centralized UI libraries. Build and test tooling (like storybook) live outside of that relationship to ensure weak coupling.

```text
 MonoRepo/                        PNPM Workspace
     │
     ├─ ...
     │                            Outside components
     ├─ tools/                    are referenced via
     │  └── storybook ◄──┬────┐   symlinked packages
     │                   │    │   in node_modules.
     ├─ ui/              │    │
     │  ├── Component────┘    │   Storybook Issues:
     │  ├── Component         │
     │  └── ...    │          │   · TSDocs to Arg-Docs
     │             │          │   · "New File" HMR
     └─ views/     ▼          │   · Recursions / Broken
        ├── SampleView────────┘   · ...
        └── ...
```

### How to run Storybook Issues Inspection

Clone [D1no/reproduction-storybook-symlinks-pnpm](https://github.com/D1no/reproduction-storybook-symlinks-pnpm)

```bash
git clone git@github.com:D1no/reproduction-storybook-symlinks-pnpm.git && cd reproduction-storybook-symlinks-pnpm.git
```

and install

```bash
pnpm install
```

> _For install with empty cache, run_
>
> ```bash
> pnpm clean-install
> ```

then for the case run the respective pnpm script...
> these are defined in [main.ts](https://github.com/D1no/reproduction-storybook-symlinks-pnpm/blob/master/tools/.storybook/main.ts) under `tools/.storybook/main.ts`

### Expectation

After running `pnpx storybook@next init --builder vite`, official storybook features should function _without any additional configuration_ of loaders, builders or other down stream dependencies installed by storybook.

> ❗️ Preview images are from Version `7.0.0-rc.4` and NOT continuously updated to the latest version.

---

#### Case 1: Components inside storybook folder

![1_local_symlink_stories-animated](https://user-images.githubusercontent.com/2397125/226085212-8a8a3a07-4ec9-4ecb-ab13-b7d41073132d.png)

```bash
pnpm run storybook:case_1
```

Components that are _inside_ of the storybook root folder (`../stories`) will:

- [x] For real files (`tools/stories/Component`)
  - [x] Render successfully in storybook
  - [x] Have JSDocs converted to story docs
  - [x] Have HMR show new stories files (while running, co-located `another.stories-hmr.tsx` to `.stories.tsx`)
- [ ] For symbolic links (`tools/stories/ComponentAsSymlink`)
  - [x] Render successfully in storybook
  - [ ] Have JSDocs converted to story docs
  - [ ] Have HMR show new stories files (while running, co-located `another.stories-hmr.tsx` to `.stories.tsx`)

---

#### Case 2-1: Components outside storybook folder

![2-1_manual_outside_root_stories-animated](https://user-images.githubusercontent.com/2397125/226085223-b739c07d-7ce5-4d41-b0c4-cb6182e07958.png)

```bash
pnpm run storybook:case_2-1
```

Components that are _outside_ of the storybook root folder but referenced with a relative path (`../../ui/`) will:

- [x] Render successfully in storybook
- [ ] Have JSDocs converted to story docs
- [ ] Have HMR show new stories files (while running, co-located `another.stories-hmr.tsx` to `.stories.tsx`)

---

#### Case 2-2: Single capitalized component folder outside storybook

![2-2_manual_outside_root_stories_direct_to_capitalized_component_folder](https://user-images.githubusercontent.com/2397125/226085238-4d4b05ed-d1ce-4fca-be4b-75246720c0d0.png)

```bash
pnpm run storybook:case_2-2
```

A single component that is _outside_ of the storybook root folder but referenced with a relative path (`../../ui/Component`) to its _capitalized_ folder, will:

<details>
<summary>❌ ERROR: WARN 🚨 Unable to index ./../ui/Component/index.stories.tsx</summary>

```bash
tools storybook: WARN 🚨 Unable to index ./../ui/Component/index.stories.tsx:
tools storybook: WARN   Error: Invalid kind '', must include alphanumeric characters
tools storybook: WARN     at m (/Users/worker/development/_REPRODUCTIONS/reproduction-storybook-symlinks-pnpm/node_modules/.pnpm/@storybook+csf@0.0.2-next.10/node_modules/@storybook/csf/dist/index.js:3:3033)
tools storybook: WARN     at N (/Users/worker/development/_REPRODUCTIONS/reproduction-storybook-symlinks-pnpm/node_modules/.pnpm/@storybook+csf@0.0.2-next.10/node_modules/@storybook/csf/dist/index.js:3:3126)
tools storybook: WARN     at /Users/worker/development/_REPRODUCTIONS/reproduction-storybook-symlinks-pnpm/node_modules/.pnpm/@storybook+csf-tools@7.0.0-rc.4/node_modules/@storybook/csf-tools/dist/index.js:18:343
tools storybook: WARN     at Array.reduce (<anonymous>)
tools storybook: WARN     at CsfFile.parse (/Users/worker/development/_REPRODUCTIONS/reproduction-storybook-symlinks-pnpm/node_modules/.pnpm/@storybook+csf-tools@7.0.0-rc.4/node_modules/@storybook/csf-tools/dist/index.js:18:230)
tools storybook: WARN     at Object.indexer (/Users/worker/development/_REPRODUCTIONS/reproduction-storybook-symlinks-pnpm/node_modules/.pnpm/@storybook+core-server@7.0.0-rc.4/node_modules/@storybook/core-server/dist/presets/common-preset.js:8:2055)
tools storybook: WARN     at async StoryIndexGenerator.extractStories (/Users/worker/development/_REPRODUCTIONS/reproduction-storybook-symlinks-pnpm/node_modules/.pnpm/@storybook+core-server@7.0.0-rc.4/node_modules/@storybook/core-server/dist/index.js:13:3554)
tools storybook: WARN     at async /Users/worker/development/_REPRODUCTIONS/reproduction-storybook-symlinks-pnpm/node_modules/.pnpm/@storybook+core-server@7.0.0-rc.4/node_modules/@storybook/core-server/dist/index.js:13:1869
tools storybook: WARN     at async Promise.all (index 0)
tools storybook: WARN     at async Promise.all (index 0)
```

</details>

- [ ] Render successfully in storybook
- [ ] Have JSDocs converted to story docs
- [ ] Have HMR show new stories files (while running, co-located `another.stories-hmr.tsx` to `.stories.tsx`)

---

#### Case 3: Components added to storybook from `pnpm` workspace

![3_proper_workspace_stories_but_recursion](https://user-images.githubusercontent.com/2397125/226085245-c6b5b8e7-c27f-423b-9486-d8949eb74a7b.png)

```bash
pnpm run storybook:case_3
```

Components that are _outside_ of the storybook root folder but referenced via `pnpm` workspaces, therefore located in `../node_modules/@repo/` as a symlink will:

<details>
<summary>❌ ERROR: importers[path] is not a function</summary>

```bash
importers[path] is not a function
TypeError: importers[path] is not a function
    at StoryStore.importFn (http://localhost:6006/virtual:/@storybook/builder-vite/storybook-stories.js:6:31)
    at StoryStore.loadCSFFileByStoryId (http://localhost:6006/sb-preview/runtime.mjs:40:8376)
    at StoryStore.loadStory (http://localhost:6006/sb-preview/runtime.mjs:40:9563)
    at async http://localhost:6006/sb-preview/runtime.mjs:74:9003
    at async StoryRender.runPhase (http://localhost:6006/sb-preview/runtime.mjs:74:8764)
    at async StoryRender.prepare (http://localhost:6006/sb-preview/runtime.mjs:74:8922)
    at async PreviewWeb.renderSelection (http://localhost:6006/sb-preview/runtime.mjs:94:3120)
```

</details>

- [ ] Render successfully in storybook
- [ ] Have JSDocs converted to story docs
- [ ] Have HMR show new stories files (while running, co-located `another.stories-hmr.tsx` to `.stories.tsx`)
- [ ] Detects symlink recursion or provides easy way to exclude them

---

#### Case 4: Components via `pnpm` with globby workaround in `main.ts` to avoid `node_modules` recursion

![4_proper_workspace_stories_trying_to_avoid_recursion_with_glob-animation](https://user-images.githubusercontent.com/2397125/226085251-72b615f6-88e9-4178-94aa-d44c8f9eef95.png)

```bash
pnpm run storybook:case_4
# or
pnpm run storybook
```

Components that are _outside_ of the storybook root folder but referenced via `pnpm` workspaces, ingested via a negative glob to avoid recursion as `../node_modules/@repo/**!(node_modules)/**!(node_modules)/*.stories.@(js|jsx|ts|tsx)` will:

- [x] Render successfully in storybook
- [ ] Have JSDocs converted to story docs
- [ ] Have HMR show new stories files (while running, co-located `another.stories-hmr.tsx` to `.stories.tsx`)
- [ ] Detects symlink recursion or provides easy way to exclude them

## System

Via `pnpx sb@next info` on 2023-03-18

```cpp
Environment Info:

  System:
    OS: macOS 13.2.1
    CPU: (10) arm64 Apple M1 Max
  Binaries:
    Node: 18.14.1 - ~/.nvs/default/bin/node
    npm: 9.3.1 - ~/.nvs/default/bin/npm
  Browsers:
    Chrome: 111.0.5563.64
    Firefox: 97.0.1
    Safari: 16.3
  npmPackages:
    @storybook/addon-essentials: ^7.0.0-rc.4 => 7.0.0-rc.4
    @storybook/addon-interactions: ^7.0.0-rc.4 => 7.0.0-rc.4
    @storybook/addon-links: ^7.0.0-rc.4 => 7.0.0-rc.4
    @storybook/blocks: ^7.0.0-rc.4 => 7.0.0-rc.4
    @storybook/react: ^7.0.0-rc.4 => 7.0.0-rc.4
    @storybook/react-vite: ^7.0.0-rc.4 => 7.0.0-rc.4
    @storybook/testing-library: ^0.0.14-next.1 => 0.0.14-next.1
```


# Original Issue

> [Bug]: No JSDoc generation when story outside root or symlinked (MonoRepo Blocker) `ts` + `vite` + `^storybook@7.0.0-rc.1`

<details>
<summary>Show</summary>

### Describe the bug

Spend a couple hours trying to get storybooks typescript JSDoc to storybook ArgDocs working, but to no avail. As typical with MonoRepos, the UI library sits outside of the testing / build toolchain.

Components render, but there is no ArgDocs generation...

- when stories are included via `"../../"` in `.storybook/main.ts`
or
- when stories are included via a symlink (pnpm workspaces mount project libraries into `node_modules/*lib*/**/*stories*`) — but symlinks anywhere wont work for docgen (see reproduction)

This means docgen doesn't work here:

```js
.
└── MonoRepo/           // git root
    ├── tools/
    │   ├── ...
    │   └── storybook   // <- Storybook root
    │                    
    └── ui/             // React Components
        ├── Component
        ├── Component
        └── ...
```

### To Reproduce

You find a reproduction as the following git repo:
https://github.com/D1no/reproduction-storybook-symlinks-pnpm

The same component is included as (1) local copy inside `stories/`, (2) as reference in `.storybook/main.ts` and as a (3) symbolic link into `stories/`.

✅ All three types render successfully in storybook.

❌ Only variant (1) has JSDoc converted to story docs (!)

Exact same component and story, but as you see = different location = no JSDocGen.
![storybook_no_jsdocgen](https://user-images.githubusercontent.com/2397125/222922498-ed8c6d83-c2f8-4f0f-b570-30e955ccdc6c.gif)

The Component `index.tsx`

```ts
import React from "react";

interface ComponentProps {
  /**
   * Set the text of the component. This is a JSDoc of the text property.
   */
  text?: string;
}

/**
 * This is the description of the Component as JSDoc.
 */
const Component = ({ text }: ComponentProps) => {
  return <div>This component text says: {text}</div>;
};

export default Component;

```

The Component Story `index.stories.tsx`

```ts
import type { Meta, StoryObj } from "@storybook/react";

import { default as LocalComponent } from "./index";

// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
const meta = {
  title: "stories/Component (local)",
  component: LocalComponent,
  tags: ["autodocs"],
} satisfies Meta<typeof LocalComponent>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
export const Component: Story = {
  args: {
    text: "I am a local component inside of tools/stories/Component. And I have docs from the JSDoc comments.",
  },
};

```

### System

```shell
Environment Info:

  System:
    OS: macOS 13.2.1
    CPU: (10) arm64 Apple M1 Max
  Binaries:
    Node: 18.14.1 - ~/.nvs/default/bin/node
    npm: 9.3.1 - ~/.nvs/default/bin/npm
  Browsers:
    Chrome: 110.0.5481.177
    Firefox: 97.0.1
    Safari: 16.3
  npmPackages:
    @storybook/addon-essentials: ^7.0.0-beta.61 => 7.0.0-beta.61
    @storybook/addon-interactions: ^7.0.0-beta.61 => 7.0.0-beta.61
    @storybook/addon-links: ^7.0.0-beta.61 => 7.0.0-beta.61
    @storybook/blocks: ^7.0.0-alpha.8 => 7.0.0-alpha.8
    @storybook/react: ^7.0.0-beta.61 => 7.0.0-beta.61
    @storybook/react-vite: ^7.0.0-beta.61 => 7.0.0-beta.61
    @storybook/testing-library: ^0.0.14-next.1 => 0.0.14-next.1
```


### Additional context

I have the feeling, the problem lies in [@joshwooding/vite-plugin-react-docgen-typescript](https://github.com/joshwooding/vite-plugin-react-docgen-typescript) 👀 ping @joshwooding

<sub>_I really love storybook and have mad respect of what you guys are dealing with. For me, to get storybook into more larger projects, it would be important to have reliable mono repository functionality. In the past I recall from engineers issues with SB, be it with nx (or here, pnpm), that some features seem to always not quite work... Not sure what the SB test suit is, but it would be nice to know that common mono repo tools (pnpm worspaces, nx, turborepo, lerna, etc) are — in a basic set-up — in your test suit for features and add-ons. As single root projects seem to be a thing of the past (which is a great thing for test driven development and team scalability). Anyway: Tip to the hat; I hope this repro is helpful!_<sub>

</details>