Storybook9 + React16 + Webpack5 项目启动时无法索引Story文件的问题求助
我来帮你梳理下可能的问题点和解决思路哈,从你给出的错误信息和代码来看,大概率是Storybook9的文档索引器(就是你开启的autodocs用到的功能)处理不了你story文件里的React.lazy异步加载逻辑。
先拆解下错误:“Unable to index ... No matching indexer found”这个报错,一般是Storybook在扫描story文件生成自动文档时,遇到了它没法解析的语法或者组件结构,你的情况里,就是那个带1秒延迟的React.lazy加载组件。
Storybook的索引器是快速扫描文件的,不会等你的异步setTimeout完成,当它碰到这种延迟加载的lazy组件时,就会懵圈,找不到对应的索引规则,直接抛出错误。
给你几个具体的排查和解决步骤:
第一步:先验证是不是lazy加载的问题
先临时把story里的lazy加载改成同步导入,看看能不能正常启动:
// 替换原来的lazy加载代码 import InnerComponent from './mockComponent'; export default { title: 'Button', component: Button, tags: ['autodocs'], args: { Loader, Component: InnerComponent, // 直接用同步导入的组件 }, };
然后重新跑npm run storybook,如果能正常启动,那就实锤是lazy加载的问题了。
第二步:适配Storybook的索引逻辑调整lazy组件的用法
既然确认是lazy的问题,我们可以调整代码让它兼容Storybook的索引器:
方案A:把lazy加载移到具体的Story渲染函数里
不要在默认导出的args里直接传lazy组件,而是在单个Story的render函数里动态加载:
import React, { lazy } from 'react'; import { fn } from 'storybook/test'; import Button from '..'; import Loader from './Loader'; // 可以单独把Loader抽成同步组件 export default { title: 'Button', component: Button, tags: ['autodocs'], args: { Loader, // 这里先不传Component,或者传一个默认的同步占位组件 }, }; // 具体的Story里再用lazy加载 export const WithLazyComponent = { render: (args) => { const InnerComponent = lazy(() => import('./mockComponent')); return <Button {...args} Component={InnerComponent} />; }, };
这样索引器扫描默认导出的时候,不会碰到异步逻辑,就能正常索引了,而实际运行Story的时候,lazy加载的逻辑也能正常工作。
方案B:去掉lazy加载的延迟(如果你的延迟只是测试用的)
如果那个1秒延迟只是为了模拟加载状态,不是业务必须的,可以直接去掉setTimeout,改成普通的lazy加载:
const InnerComponent = lazy(() => import('./mockComponent'));
Storybook的索引器可能能处理不带延迟的lazy组件,你可以试试这个写法。
第三步:检查配置的兼容性(可选)
你的main.js配置里开了fsCache和lazyCompilation,这两个是Webpack5的特性,对于React16这种比较老的版本,可能会有兼容性问题,你可以临时关掉试试:
framework: { name: "@storybook/react-webpack5", options: { fsCache: false, lazyCompilation: false, }, },
另外,确保你的Babel配置是适配React16的,比如@babel/preset-react的版本要和React16兼容,不要用太新的版本。
最后再确认下路径匹配
虽然你的stories路径配置看起来是对的,但可以临时改成更宽松的规则,比如"../src/**/*.story.@(js|jsx)",排除路径匹配的问题,不过这个概率比较低。
先从第一步开始试,应该就能定位到问题啦!
内容来源于stack exchange

