Storybook 7迁移问题:复用桌面故事创建移动端故事的最佳实现方案(解决重导出失效与ESLint报错)
嘿,我刚帮几个朋友解决过类似的Storybook 7迁移问题,你的场景太典型了——之前用重导出省了不少复制粘贴的功夫,结果到7.x直接失效还报ESLint错,确实头疼。下面给你几个靠谱的解决方案,都是符合Storybook 7新规范的:
方案一:官方推荐的「基础元数据+模板复用」(最优雅,适合长期维护)
Storybook 7更鼓励把公共逻辑抽离成可复用的模板和基础元数据,这样既避免重复代码,又能让每个故事文件都符合新的检测规则。
步骤1:创建公共基础文件
先新建一个demo.stories.tsx,把桌面/移动端共用的故事模板和基础配置放进去:
import { Demo } from './index'; import type { Layout } from './index'; // 定义通用的故事渲染模板 export const Template = ({ layout }: { layout?: Layout }) => <Demo layout={layout} />; // 基础元数据(可以在这里定义通用的参数、文档、argTypes等) export const baseMeta = { component: Demo, argTypes: { layout: { control: 'select', options: ['desktop', 'mobile'] } } };
步骤2:改造桌面端故事文件
修改desktop.stories.tsx,继承基础元数据并设置专属配置:
import { baseMeta, Template } from './demo.stories'; export default { ...baseMeta, title: 'demo/desktop', args: { layout: 'desktop' } }; // 绑定模板生成桌面端故事 export const Story = Template.bind({});
步骤3:改造移动端故事文件
同样修改mobile.stories.tsx,只需要替换title和args里的layout值:
import { baseMeta, Template } from './demo.stories'; export default { ...baseMeta, title: 'demo/mobile', args: { layout: 'mobile' } }; // 绑定模板生成移动端故事 export const Story = Template.bind({});
这样每个文件都有明确的Story导出,ESLint的story-exports规则会直接通过,而且Storybook能正确识别两个独立的故事节点。后续新增故事时,只需要在基础模板里加逻辑,两端自动同步,完美解决你的痛点。
方案二:显式导出故事(快速改造,适合小项目)
如果不想新增公共文件,也可以直接修改移动端的故事文件,显式导入并复用桌面端的故事模板,同时覆盖参数:
// mobile.stories.tsx import { Story as DesktopStory } from './desktop.stories'; export default { title: 'demo/mobile', args: { layout: 'mobile' } }; // 复制桌面端故事的逻辑,同时替换移动端的layout参数 export const Story = DesktopStory.bind({}); Story.args = { layout: 'mobile' };
这个方案的核心是用bind({})复制故事实例,再覆盖args,既保留了复用逻辑,又满足了Storybook 7对「每个文件必须有自己的故事导出」的要求,ESLint也不会再报错。
方案三:临时调整ESLint规则(不推荐,仅应急)
如果你只是临时需要过渡,不想大规模改代码,可以在ESLint配置里放宽storybook/story-exports规则,允许从其他故事文件重导出:
// .eslintrc.js 或 .eslintrc.json { "rules": { "storybook/story-exports": ["error", { "allowExportsFrom": ["*.stories.tsx"] }] } }
但要注意:这个方案只能解决ESLint报错,Storybook 7本身对重导出的故事识别还是有问题,移动端故事大概率还是不会显示在侧边栏,所以只适合临时应急,长期来看还是推荐前两种方案。
为什么原来的方式失效了?
Storybook 7重构了故事的检测逻辑,不再识别跨文件重导出的故事;同时官方的ESLint插件也更新了规则,要求每个故事文件必须有属于自己的故事导出,不能只依赖export *这种方式。
备注:内容来源于stack exchange,提问作者kir

