babel-plugin-storybook-csf-title
一个 Babel 插件,用于在编译时为 Storybook CSF 故事生成标题,通常基于故事文件的名称。
用法
该插件根据要作为插件选项提供的 toTitle
函数的结果,为所有转换后的文件添加一个 title
属性。
假设 toTitle: () => 'foo'
,有三种一般场景
1️⃣ 文件未提供默认导出
在这种情况下,该插件创建一个默认导出 { title: "foo" }
。
例如:
import React from 'react';
import Component from './index';
export const Example = () => <Component />;
被转换为
import React from 'react';
import Component from './index';
export const Example = () => <Component />;
export default { title: 'foo' };
2️⃣ 文件提供一个对象作为其默认导出
在这种情况下,该插件将 title: foo
属性添加到现有导出。
例如:
import React from 'react';
import Component from './index';
export default {
something: 'something'
};
export const Example = () => <Component />;
被转换为
import React from 'react';
import Component from './index';
export default {
title: 'foo'
something: 'something'
};
export const Example = () => <Component />;
如果现有导出已经包含 title
属性,则会抛出错误。
3️⃣ 文件提供一个非对象作为其默认导出
如果设置了 renameDefaultExportsTo
选项,该插件会假设默认导出是一个组件,并将该组件移动到一个名为 ${renameDefaultExportsTo}
的命名导出。然后它创建一个默认导出 { title: "foo" }
。
例如,假设 renameDefaultExportsTo
为 "Default"
,
import React from 'react';
import Component from './index';
export default () => <Component />;
被转换为
import React from 'react';
import Component from './index';
export const Default = () => <Component />;
export default {
title: 'foo'
};
如果 ${renameDefaultExportsTo}
导出已经存在,则会抛出错误。
安装
安装该插件,例如通过 yarn
;
yarn add --dev babel-plugin-storybook-csf-title
在您的 Babel 配置中,添加 babel-plugin-storybook-csf-title
作为插件
plugins: [
['babel-plugin-storybook-csf-title', { toTitle: require('./your-to-title-function') }],
]
请注意,该插件实际上只对故事文件有意义。您需要确保它只应用于这些文件,例如像这样
/* add plugin to babel, however disable it by default */
plugins: [
['babel-plugin-storybook-csf-title', false],
],
/* enable the plugin for all files that match your story name pattern */
overrides: [{
include: /\/stories\.(ts|tsx)$/,
plugins: [
['babel-plugin-storybook-csf-title', { toTitle: require('./your-to-title-function') }]
]
}]
选项
该插件接受三个选项,toTitle
(必需)、ifTitleFound
(可选)和 renameDefaultExportsTo
(可选)
-
toTitle
是一个函数,它为每个被转换的故事文件接收 Babel 的state
对象,并且必须以字符串形式返回故事文件的标题。大多数toTitle
实现将根据state.filename
做出决定。 -
ifTitleFound
是一个可选的字符串值,可以设置为'skip'
- 如果标题已经手动在代码中指定,则跳过添加标题undefined
(或任何其他值) - 如果处理一个已经定义了标题的文件,则引发错误
-
renameDefaultExportsTo
是一个可选的字符串值,用于控制上面描述的场景 3。默认情况下它为undefined
。
生成有意义的故事名称
在大多数情况下,故事名称将根据故事文件的名称生成。以下是一个针对 yarn workspaces
样式单仓库设置的 toTitle
的可能实现
const path = require('path');
const pkgUp = require('pkg-up');
module.exports = (state) => {
// find the closest package.json
const packageJsonPath = pkgUp.sync({ cwd: state.filename });
// read the package.json
const packageJson = require(packageJsonPath);
// get the path of the story file relative to the package root
const { dir: packageJsonDir } = path.parse(packageJsonPath);
const { dir: fileDir, name: fileName } = path.parse(path.relative(packageJsonDir, state.filename));
const storybookPath = [
// package name; "/" has meaning to storybook, hence replace a possible "/" by "|"
packageJson.name.replace('/', '|'),
// file dir
...fileDir.split(path.sep),
];
// handle file names
if (fileName === 'examples' || fileName === 'stories') {
// nothing to do
} else if (fileName.endsWith('.stories')) {
storybookPath.push(fileName.slice(0, '.stories'.length + 1));
} else if (fileName.endsWith('.examples')) {
storybookPath.push(fileName.slice(0, '.examples'.length + 1));
}
return storybookPath.join('/');
}
贡献
欢迎对 babel-plugin-storybook-csf-title
进行贡献!请参阅 CONTRIBUTING.md 了解详细信息。
许可证
版权所有 (c) 2020 Atlassian 及其他人。Apache 2.0 许可,请参阅 LICENSE 文件。