storybookjs/storybook

[Bug]: Stories can't be found when CWD is nested within a complex directory structure

Open

#21,468 建立於 2023年3月7日

在 GitHub 查看
 (0 留言) (5 反應) (0 負責人)TypeScript (89,909 star) (10,058 fork)batch import
bugcorehas workaroundhelp wantedsev:S3

描述

Describe the bug

Setup

In a monorepo:

  1. Storybook configuration in the root
  2. Multiple packages, with stories in them
  3. Storybook is not started from root, but rather from one of the packages - like a "core" package - and the --config-dir flag pointing up to the directory in the root.*

With a stories glob that is like this: '../packages/@(core|other)/src/**/*.stories.@(js|jsx|ts|tsx)'.

* Why not just start Storybook from the root? Svelte-Vite/SvelteKit setups require that svelte.config.js are in CWD (This is a Svelte requirement, nothing related to Storybook), and if those configs live in each package, you have to start Storybook from a package for Svelte to pick up that config. There might be other reasons too.

This setup was discovered when doing 7.0 QA on the SvelteUI repo.

The bug

The sidebar fails to load with an error when indexing the stories:

Unable to index files:
- ./src/stories/Introduction.mdx: Cannot read properties of undefined (reading 'toLowerCase')
- ./src/stories/Button.stories.js: Cannot read properties of undefined (reading 'toLowerCase')
- ./src/stories/Header.stories.js: Cannot read properties of undefined (reading 'toLowerCase')
- ./src/stories/Page.stories.js: Cannot read properties of undefined (reading 'toLowerCase')

The problem is that each story's importPathMatcher is a regex that is supposed to be relative to CWD, but based on the stories glob. But if the glob cannot easily be converted to a relative CWD dir - because of the @(core|other) part - it won't be relative to CWD, and then it won't match the story file name that is relative to CWD. Here's what a console.log at userOrAutoTitleFromSpecifier https://github.com/storybookjs/storybook/blob/next/code/lib/preview-api/src/modules/store/autoTitle.ts#L66 looks like for a failing story:

{
  normalizedFileName: './src/stories/Button.stories.js',
  directory: '..',
  importPathMatcher: /^(?:\.\.\/(core|other)\/src(?:\/(?!\.)(?:(?:(?!(?:^|\/)\.).)*?)\/|\/|$)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$/,
  titlePrefix: '',
  userTitle: 'Button',
  fileName: './src/stories/Button.stories.js'
}

With the workaround below applied, here's what a similar console.log of a successful case looks like:

{
  normalizedFileName: './src/stories/Button.stories.js',
  directory: './src',
  importPathMatcher: /^\.[\\/](?:src(?:\/(?!\.)(?:(?:(?!(?:^|\/)\.).)*?)\/|\/|$)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$/,
  titlePrefix: '',
  userTitle: 'Button',
  fileName: './src/stories/Button.stories.js'
}

That regex does match the fileName.

To Reproduce

  1. Open reproduction at: https://stackblitz.com/edit/github-1xafeq?file=package.json
  2. Start storybook with yarn storybook (which changes CWD to packages/core)

System

No response

Additional context

I believe the logic that fails to take this whole edge case into account lives somewhere in normalizeStoriesEntry. https://github.com/storybookjs/storybook/blob/next/code/lib/core-common/src/utils/normalize-stories.ts#L34

There are a lot of pieces that makes this bug appear, so I would consider this a very edgy edge-case.

Workaround

If the stories glob is changed:

from

['../packages/@(core|other)/src/**/*.stories.@(js|jsx|ts|tsx)']

to

[
  '../packages/core/src/**/*.stories.@(js|jsx|ts|tsx)',
  '../packages/other/src/**/*.stories.@(js|jsx|ts|tsx)'
]

The "stories glob to CWD relative regex"-logic works.

貢獻者指南