babel-plugin-storybook-csf-title
一個 Babel 外掛程式,可在編譯時期為 Storybook CSF stories 產生標題,通常基於 story 檔案的檔名。
用法
這個外掛程式會根據 `toTitle` 函數的結果,為所有轉換後的檔案添加 `title` 屬性,而 `toTitle` 函數將作為外掛程式的選項提供。
假設 `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') }],
]
請注意,這個外掛程式實際上只對 story 檔案有意義。你會希望確保它只應用於這些檔案,例如像這樣:
/* 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` 是一個函數,對於每個被轉換的 story 檔案,它會接收 Babel 的 `state` 物件,並且必須以字串形式回傳 story 檔案的標題。大多數 `toTitle` 實作會根據 `state.filename` 做出決定。
-
`ifTitleFound` 是一個選填的字串值,可以設定為:
- `'skip'` - 如果標題已在程式碼中手動指定,則跳過新增標題
- `undefined` (或任何其他值) - 如果處理的檔案已經定義了標題,則引發錯誤
-
`renameDefaultExportsTo` 是一個選填的字串值,用於控制如上所述的情境 3。預設值為 `undefined`。
產生有意義的 story 名稱
在大多數情況下,story 名稱將基於 story 檔案的檔名產生。以下是一個可能的 `toTitle` 實作,適用於 `yarn workspaces` 風格的 monorepo 設定:
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 檔案。