[Bug]: Stories can't be found when CWD is nested within a complex directory structure
#21,468 创建于 2023年3月7日
描述
Describe the bug
Setup
In a monorepo:
- Storybook configuration in the root
- Multiple packages, with stories in them
- Storybook is not started from root, but rather from one of the packages - like a "core" package - and the
--config-dirflag 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
- Open reproduction at: https://stackblitz.com/edit/github-1xafeq?file=package.json
- Start storybook with
yarn storybook(which changes CWD topackages/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.