首页
/ Storybook 层级分隔符的废弃与自动迁移:eslint-plugin-storybook 的 hierarchy-separator 规则详解

Storybook 层级分隔符的废弃与自动迁移:eslint-plugin-storybook 的 hierarchy-separator 规则详解

2026-09-06 18:11:29作者:宣海椒Queenly

导读

Storybook 从 6.0 起移除了侧边栏中可自定义的层级分隔符,组件(story kind)的分组路径现在统一使用 / 且不可配置。eslint-plugin-storybook 中的 storybook/hierarchy-separator 规则专门用于检查 CSF 元数据(meta)的 title 中仍在使用已被废弃的 | 分隔符的写法,帮助开发者在升级 Storybook 后保持故事侧边栏分组正确、目录结构干净。读完本文,你将掌握该规则的触发条件、配置与覆盖方法,并学会使用官方 codemod 一键批量迁移历史代码。

背景:为什么分隔符只能使用 /

在 Storybook 的早期版本中,开发者可以通过 title 字段控制故事在侧边栏中的分组(hierarchy)。当时不仅支持 /,还支持用 | 表示故事"根"分组、用 . 表示路径层级,这些分隔符甚至可以在配置中自定义。从 Storybook 5.3 开始,官方着手"简化层级分隔符"(simplified hierarchy separators),将规则收敛为单一分隔符 /;到 6.0 正式移除了自定义分隔符能力,仅保留 / 且不可配置。相关演进记录可查看仓库根目录的 MIGRATION.md

因此,如果你的存量代码中仍有类似 title: 'Components|Forms/Input' 的写法,| 不会被识别为分组边界,故事可能被折叠成一个带特殊字符的奇怪名字,或者分组与预期完全不符。你需要把这类分隔符全部改为 /

规则做什么:扫描 meta.title 中的废弃分隔符

storybook/hierarchy-separator 规则所做的工作非常聚焦:它会解析每个 story 文件默认导出的 meta 对象,读取其中的 title 字符串字面量,并检查其中是否包含废弃的 | 字符。一旦发现,即以警告(warn)级别上报,并同时提供一个可自动修复(--fix)的方案与一个修复建议(suggestion)。

该规则对如下 不正确 的代码报错:

export default {
  title: 'Components|Forms/Input', // '|' 是已废弃的层级分隔符
  component: Input,
};

正确写法应统一使用 /

export default {
  title: 'Components/Forms/Input', // 全部使用 '/' 分隔层级
  component: Input,
};

规则实现 的源码可以看到核心逻辑:规则仅当 metaTitle.includes('|') 时触发上报,上报信息包含原始 title(Deprecated hierarchy separator in title property: {{metaTitle}});修复函数 fix 会把字符串中的全部 | 替换为 /metaTitle.replace(/\|/g, '/')),并作为 suggestion(Use correct separators)一并提供。

触发与不触发:从测试用例看边界

规则只扫描 默认导出(export default)的 meta 对象 中的 title。参考 规则测试用例

  • 直接内联对象的写法会触发检测,例如 export default { title: 'Examples|Components/Button' }
  • meta 先赋值给变量再默认导出同样会被检测,例如:
    const meta = { title: 'Examples|Components/Button' }
    export default meta
    
  • 不会误报的情况包括:export default { title: 'Examples.Components' }(注意,title 中仅含 . 不会被本规则拦截)、标准的 / 分隔标题 title: 'Examples/Components/Button'、带类型断言的写法 title: '...' as ComponentMeta<typeof Button>,以及 meta 使用了展开运算符的 export default { ...props }(此时规则无法确定 title 的真实值)。

需要特别说明:规则文档提到 |. 都建议改为 /,但从测试可见,本规则的实际检测范围聚焦在废弃根分隔符 | 上,单独使用 . 作为路径的标题不会触发该规则的告警,迁移时请自行留意这类写法。

规则在哪些配置集中默认开启

该规则被包含在以下 6 个官方推荐配置集中,且默认均为 warn(警告级别):

配置集(eslintrc 风格) 配置集(flat config 风格)
csf flat/csf
recommended flat/recommended
csf-strict flat/csf-strict

你可以在 csf 配置源文件recommended 配置源文件 中看到 'storybook/hierarchy-separator': 'warn' 的默认声明。也就是说,只要你在项目里继承了 plugin:storybook/recommended(eslintrc 风格)或 storybook.configs['flat/recommended'](flat config 风格),该规则就会自动只作用于你的 *.stories.* / *.story.* 故事文件。

安装与配置

安装插件

eslint-plugin-storybook 无需额外安装 Storybook 即可使用(插件自带所需依赖,适合在 monorepo 共享 ESLint 预设中引用):

npm install eslint-plugin-storybook --save-dev
# 或
yarn add eslint-plugin-storybook --dev

通过 extends 启用(eslintrc 风格)

在你的 .eslintrc.* 中继承推荐配置,插件会自动只应用于符合 *.stories.**.story.* 模式的文件:

{
  "extends": ["plugin:storybook/recommended"]
}

通过 flat config 启用(ESLint v9 / v8.57+)

import storybook from 'eslint-plugin-storybook';

export default [
  // 添加其他通用规则集,如 js.configs.recommended ...
  ...storybook.configs['flat/recommended'],
];

单独启用、提级或关闭

如果你未继承包含它的推荐配置,或想调整严重级别,可以在覆盖(overrides)中单独设置,注意只对故事文件生效:

eslintrc 风格:

{
  "overrides": [
    {
      "files": ["**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)"],
      "rules": {
        "storybook/hierarchy-separator": "error" // 也可设为 "off" 关闭
      }
    }
  ]
}

flat config 风格:

import storybook from 'eslint-plugin-storybook';

export default [
  ...storybook.configs['flat/recommended'],
  {
    files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)'],
    rules: {
      // 提级为 error(阻止构建/提交),或置 "off" 关闭
      'storybook/hierarchy-separator': 'error',
    },
  },
];

更多配置方式(包括与 oxlint 配合使用的示例)参见 eslint-plugin-storybook README

自动修复与 codemod 批量迁移

ESLint --fix 自动修复

由于规则标记了 fixable: 'code',你可以直接在故事文件上运行 ESLint 自动修复,把 | 全部替换为 /

npx eslint "src/**/*.stories.{js,ts,jsx,tsx}" --fix

官方 codemod 一键迁移

如果你的历史代码较多,更推荐使用官方提供的 upgrade-hierarchy-separators codemod,在项目根目录运行即可批量转换所有故事文件:

npx storybook@latest migrate upgrade-hierarchy-separators --glob="*/**/*.stories.@(tsx|jsx|ts|js)"

该 codemod 属于 @storybook/codemod 工具集(源码位于 code/lib/codemod),其针对 CSF 的转换效果可参考 upgrade-hierarchy-separators 的测试快照,例如把 title: 'Foo|Bar/baz/whatever' 转换为 title: 'Foo/Bar/baz/whatever'。对于使用了旧版 storiesOf API 的文件同样适用。需要留意的是,官方 MIGRATION 指南明确指出:codemod 无法处理 .mdx 组件,MDX 文档中的层级标题需要手工修改(参见 MIGRATION.md)。

迁移后的小贴士:关于 Roots 显示

历史上使用 | 的另一个常见原因是希望得到"根(roots)"分组效果。Storybook 6.0 起默认在侧边栏为顶层分组显示可折叠的 root 入口;如果你不想要这种效果,可以在 .storybook/manager.js 中关闭:

import { addons } from '@storybook/addons';

addons.setConfig({
  showRoots: false,
});

也就是说,迁移时不必依赖 | 去制造根分组——/ 的第一段会自动成为 root 层级,是否展示可由 showRoots 控制。

小结与延伸阅读

storybook/hierarchy-separator 是一条面向迁移场景的轻量规则:它帮你发现仍在使用已废弃 | 分隔符的 CSF title,配合 --fix 或官方 upgrade-hierarchy-separators codemod 即可把全部代码迁移到单一 / 分隔符的新范式上,避免侧边栏分组错乱。

进一步阅读当前仓库中的相关资料:

登录后查看全文
热门项目推荐
相关项目推荐