storybook-loader

Description in medium
Table of Contents
Description
storybook-loader is a package for storybook to automatically load ALL files in a folder.
storybook-loader analyze the webpack's require.context return value and load the analyzed results to storyies.
After finishing the configuration, you will be free from manually adding story, as storybook-loader will load it for you automatically.
Installation
storybook-loader is available as an npm package.
npm install --save--dev storybook-loader
How to use
Steps of loading javascript component
-
Create xxx.stories.js under the target folder.
import { loadJSStories } from 'storybook-loader';
const req = require.context('./');
loadJSStories(req);
-
Create sub folder and add js files.
The following structure:
./rootPattern1.js
./folder1/pattern1.js
./folder1/pattern2.js
./folder2/pattern1.jsx
./folder2/pattern2.jsx
will display like this(rootPattern1 will be ignored):
folder1
|-pattern1
|-pattern2
folder2
|-pattern1
|-pattern2
Steps of loading markdown
-
Create xxx.stories.js under the target folder.
storybook 4.x
import { loadMDStories } from 'storybook-loader';
import { doc } from 'storybook-readme';
const req = require.context('./');
const options = {
contentFuncList: [
doc,
],
storySubFuncList: [
[
'addParameters',
[{ options: { showAddonPanel: false } }],
],
],
}
loadMDStories(req, options);
storybook 5.x
import { loadMDStories } from 'storybook-loader';
import { doc } from 'storybook-readme';
const req = require.context('./');
const options = {
contentFuncList: [
doc,
],
storySubFuncList: [
[
'addParameters',
[{ options: { showPanel: false } }],
],
],
}
loadMDStories(req, options);
-
Create sub folder and add md files.
The following structure:
./rootPattern1.md
./folder1/pattern1.md
./folder1/pattern2.md
./folder2/pattern1.md
./folder2/pattern2.md
will display like this(rootPattern1 will be ignored):
folder1
|-pattern1
|-pattern2
folder2
|-pattern1
|-pattern2
Steps of loading javascript component with markdown
When you not only like to load js components, but also show notes in control panel.
-
Create xxx.stories.js under the target folder.
storybook 4.x
import { loadJSWithNotesStories } from 'storybook-loader';
import { withNotes } from '@storybook/addon-notes';
const req = require.context('./');
const options = {
storySubFuncList: [
[
'addDecorator',
[withNotes],
],
],
};
loadJSWithNotesStories(reqList, options);
storybook 5.x
import { loadJSWithNotesStories } from 'storybook-loader';
const req = require.context('./');
loadJSWithNotesStories(reqList);
-
Create sub folder and add md files.
The following structure:
./folder1/pattern1.js
./folder1/pattern1.md
./folder1/pattern2.js
./folder1/pattern2.md
./folder2/pattern1.jsx
./folder2/pattern1.md
./folder2/pattern2.jsx
will display like this
folder1
|-pattern1 (display folder1/pattern1.md in notes panel)
|-pattern2 (display folder1/pattern2.md in notes panel)
folder2
|-pattern1 (display folder2/pattern1.md in notes panel)
|-pattern2 (display nothing in notes panel)
Instructions
parameter
1 | requireContext | 〇 | object / object list | | instance of require.context OR an object return the same architecture to require.context |
2 | options | | object | { groupByFolder: true, folderNameWhenEmpty: 'ALL' } | *see options below for more details |
3 | thirdParamMakerOptions | | object | { loader: mdLoader, formatter: formatWithNotesObject } | *see options below for more details |
options
storySubFuncList
-
Default: []
-
Description: list of sub functions in storiesOf to call
-
Attention: parameters of sub function MUST be an array
-
Example:
-- NO.1 --------------------------------------------------------
storySubFuncList: [
'subFunc1',
[ 'addDecorator', [withNotes] ],
[ 'addParameters', [{ options: { showPanel: false } }] ],
]
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
stories.subFunc1();
stories.addDecorator(withNotes);
stories.addParameters({ options: { showPanel: false } });
contentFuncList
-
Default: [ ramda.identity ]
-
Description: list of pure functions for decorating file's contents. It's useful when you want to apply hocs(High Order Component) or hofs(High Order Function) to your content like withMUITheme, withLayout...
-
Attention: functions will receive ONLY ONE parameter -- the contents (could be string or React.Component). If function has more than one parameters, you can use util.unaryFunc to apply the rest parameters and then pass it to contentFuncList.
-
Example:
-- NO.1 --------------------------------------------------------
function decPrefixMsg(content, msg) {
return `${msg}: ${content}`;
}
contentFuncList: [
util.unaryFunc(decPrefixMsg, ['MyMessage is']),
]
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
stories.add(fileName, decPrefixMsg(content, 'MyMessage is'));
-- NO.2 --------------------------------------------------------
contentFuncList: [
withMUITheme,
withLayout,
]
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
stories.add(fileName, withLayout(withMUITheme(content)));
hierarchyRoot
-
Default: ''
-
Description: prefix of stories' name. If you've enabled hierarchyRootSeparator, xxx| will be the name of hierarchyRoot.
-
Example:
-- NO.1 --------------------------------------------------------
hierarchyRoot: 'Components|'
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
storiesOf('Components|' + folderName, module);
groupByFolder
-
Default: true
-
Description: use folder name as the root stories' name.
-
Attention: If you set groupByFolder to false, all stories will be added to ONE root named by folderNameWhenEmpty(default is ALL).
-
Example:
-- NO.1 --------------------------------------------------------
groupByFolder: true
/Button/Pattern1.js
/Button/Pattern2.js
/TextField/Pattern1.js
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Button
- Pattern1
- Pattern2
TextField
- Pattern1
-- NO.2 --------------------------------------------------------
groupByFolder: false
/Button/Pattern1.js
/Button/Pattern2.js
/TextField/Pattern1.js
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
ALL
- Pattern1 (the second Pattern1 will be ignored)
- Pattern2
thirdParamMaker
-
Default: null
-
Description: function to make 3rd parameter of stories.add(xx, xx, 3rdParam).
thirdParamMaker(instance of require.context, filePath).
-
Attention: this function is called after every single file is loaded.
-
Example: createMDThirdParamMaker
sort
sortFunc
noExt
-
Default: true
-
Description: display filename in menu without extention.
-
Example:
-- NO.1 --------------------------------------------------------
noExt: true
/Button/Pattern1.js
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Button
- Pattern1
-- NO.2 --------------------------------------------------------
noExt: false
/Button/Pattern1.js
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Button
- Pattern1.js
noExtRegExp
-
Default: null
-
Description: remove extention regexp.
-
Attention: if noExt is true, will use noExtRegExp > includeRegExp > regExpFromRequireContext.
-
Example: /\.md$/ to remove markdown's extention
includeRegExp
-
Default: null
-
Description: regexp for include files by file's full path.
-
Attention: will use includeRegExp > regExpFromRequireContext.
-
Example: /\.md$/ to add *.md files only.
excludeRegExp
ignoreDotFolder
-
Default: true
-
Description: ignore files under root folder (. folder)
-
Example:
-- NO.1 --------------------------------------------------------
ignoreDotFolder: true
./Pattern1.js
/Button/Pattern1.js
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Button
- Pattern1
-- NO.2 --------------------------------------------------------
ignoreDotFolder: false
./Pattern1.js
/Button/Pattern1.js
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
.
- Pattern1
Button
- Pattern1
dotFolderName
-
Default: .
-
Description: used as folder name when it's a dot(.)
-
Example:
-- NO.1 --------------------------------------------------------
ignoreDotFolder: false
dotFolderName: 'RootFolder'
./Pattern1.js
/Button/Pattern1.js
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
RootFolder
- Pattern1
Button
- Pattern1
third parameter options
ONLY nessacerry when use loadJSWithNotesStories or loadJsonWithNotesStories. Both of them are using createMDThirdParamMaker to make 3rd parameter in stories.add(xx, xx, 3rd param).
loader
formatter
-
Default: formatWithNotesObject() in createMDThirdParamMaker
-
Description: format the content
-
Example
function formatWithNotesObject(content) {
return {
notes: {
markdown: content,
},
};
}
License
This project is licensed under the terms of the
MIT license.