Problems specifying "react-docgen" plugin in custom .babelrc
See original GitHub issueDescribe the bug
This may not be a bug, but I am under the impression that custom .babelrc
should be able to merge cleanly with the file from which it extends and should function exactly the same as if the new properties/values were simply added to the base config file. This does not seem to be the case.
To be clear, the new docs addon works pretty well out of the box along with a custom webpack config to support some loaders for css preprocessing, fonts, images. The issue I have occurs when i attempt to use my own rule for js files, replacing the original, default rule (i.e. test: /\.(mjs|jsx?)$/,
). I either encounter a Duplicate plugin/preset detected
error or the props documentation doesn’t render at all.
Steps to repro may not be clear until you review the Code Snippets section in this PR. Once reviewed, I’d love to get a recommendation on how to proceed. If any additional information is needed, just ask and I’ll get it to you post haste!
To Reproduce Steps to reproduce the behavior:
- Ensure a component story is defined for a component that has propTypes defined
- Create custom webpack config which replaces the primary js rule (
test: /\.(mjs|jsx?)$/,
) with a custom version which will utilize a root.babelrc
(observe missing props documentation) - Create
.storybook/.babelrc
which extends from another and specifies"react-docgen"
as an additional plugin (observe error in console) - Add unique name to the
"react-docgen"
plugin in custom babel config to resolve the compilation error. Spin up storybook and observe missing props documentation
Expected behavior I would much prefer to not create a custom babel config at all and instead be able to replace the primary js rule without affecting the extraction of props documentation, or perhaps have some mechanism that allows more flexibility when needing to modify the default webpack config in order to achieve parity between main app transpilation and storybook transpilation.
Code snippets
For context, here are the configs I’m working with (the only other addon I have specifically enabled is addon-a11y
and it does not appear to conflict with any of the addon-docs stuff):
Existing `.babelrc` at the root of my project
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-transform-modules-commonjs",
"@babel/plugin-transform-object-assign",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-transform-runtime"
],
"sourceRoot": "./"
}
Custom webpack config at `.storybook/webpack.config.js`
If I remove the block that replaces the primary js processing with my custom rule, the docs display as expected. However, my concern with this approach is that the default config specifies some babel plugins/presets that are not in my main project, which makes me nervous as I have less of a guarantee that the components will compile/render identically in both storybook and my main app. Since the acorn-jsx rule comes after and is most likely needed for the docs addon, I have left it alone.NOTE: I have removed/commented out certain parts of this config to try and focus on only the relevant parts.
// ... requires and variable defs...
module.exports = async ({ config, mode }) => {
const devMode = mode !== 'PRODUCTION';
// ...write original config to temp file...
// if `newRules` is undefined, remove matched rule
function replaceRule(test, ...newRules) {
const testStr = (typeof test !== 'string') ? test.toString() : test;
const ruleIndex = config.module.rules.findIndex(rule => rule.test.toString().includes(testStr));
if (ruleIndex !== -1) {
console.log(`${newRules ? 'Replacing' : 'Removing'} rule matching test: ${testStr}`);
config.module.rules.splice(ruleIndex, 1, ...newRules);
}
}
// remove ProgressPlugin to reduce console noise
console.log('Removing ProgressPlugin...');
const progressPluginIndex = config.plugins.findIndex(plugin => plugin.constructor.name === 'ProgressPlugin');
config.plugins.splice(progressPluginIndex, 1);
console.log('Adding to config.resolve.modules...');
config.resolve.modules.push(/*...*/);
console.log('Adding to config.plugins...');
config.plugins.push(/*...project-specific paths...*/);
// the default config conflicts with some of our existing rules,
// while others are necessary for storybook to work well with
// addons. to remedy the issue, we will need to surgically alter
// the rules array. the original rules may vary as addons are
// added/removed, so we'll target them by their rule strings.
// when adding addons, this processing can be re-evaluated by
// inspecting the original/modified webpack configs this file
// generates in /tmp.
// replace primary js processing to make sure transpilation has parity
// with main app
replaceRule('(mjs|jsx?)$/', {
test: /\.js$/,
exclude: /node_modules|js\/vendor/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
],
});
// remove image/font rule as we handle these cases separately
// for custom font icon set and our svg/png files
replaceRule('woff');
// now push all of our remaining rules into the array
console.log('Adding to config.module.rules...');
config.module.rules.push(
{
test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 100000,
mimetype: 'application/font-woff',
},
},
],
},
{
test: /\.(ttf|eot|svg|png)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
exclude: nonDigestRegex,
use: [
{
loader: 'url-loader',
options: {
limit: 100000,
},
},
],
},
{
test: /\.scss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader: 'sass-loader',
options: {
data: '@import "noop/index";',
includePaths: [
path.join(srcPath, 'styles'),
],
},
},
],
},
);
// ...writes modified config to file...
return config;
}
As I mentioned in the first paragraph of this issue, the docs work great if I don’t replace the primary js rule (test: /\.(mjs|jsx?)$/,
) with my own. Now I’ll walk through my attempts at getting storybook to work when I replace that rule with the custom rule as seen in my custom webpack config above.
1. Replace default core js rule with custom js rule
After replacing the rule and spinning up storybook, everything displays correctly, but my component’s props were not parsed (or were somehow lost). Under the main story it shows:
After doing a little research (looking at docs, issues, etc.), it became clear that the props get parsed using the babel-plugin-react-docgen
plugin. Given that I replaced the primary rule, I deduced that I needed to manually specify that plugin in a babel config. To test, I added "react-docgen"
to the end of the plugins array in my root .babelrc
. Hooray, the props are parsed/rendered as expected!
Unfortunately, adding that plugin to the root babel config means that the main app’s bundles will be bloated with docs information, which is undesirable.
2. Explore solution(s) to prevent transpiled docs code in main app bundle
Back to researching, I learned from the docs that I can include a custom babel config by creating .storybook/.babelrc
, so I created that custom config and copied/pasted the contents of my root config into the custom config while removing "react-docgen"
from the former and including it in the latter. I also learned from past storybook issues that using "extends": "../.babelrc",
is supported in this custom config. Both approaches failed for me with the exact same error. The root config then matched what I included at the top of this PR. The custom config and error are shown below.
Updated `.storybook/.babelrc`
{
"extends": "../.babelrc",
"plugins": [
"react-docgen"
]
}
Duplicate plugin error
The error I receive is one that has been brought up in previous storybook issues:WARN force closed preview build
ModuleBuildError: Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Duplicate plugin/preset detected.
If you'd like to use two separate instances of a plugin,
they need separate names, e.g.
plugins: [
['some-plugin', {}],
['some-plugin', {}, 'some unique name'],
]
at assertNoDuplicates (/Volumes/projects/recurly-app/snappy/node_modules/@babel/core/lib/config/config-descriptors.js:205:13)
at createDescriptors (/Volumes/projects/recurly-app/snappy/node_modules/@babel/core/lib/config/config-descriptors.js:114:3)
...
The fact that an error was thrown is quite confusing because, from the docs I was under the impression that I should get the same behavior whether or not I use a root babel config or custom config with the exact same contents:
Then Storybook will load the Babel configuration only from that file.
3. Resolve duplicate plugin issue
The error, while not providing the conflicting plugin names, does indicate a recommended solution which is to provide a unique name for the duplicate. So that’s what I did next, assuming that the react-docgen plugin was the culprit:
Add unique name to plugin in custom babel config
{
"extends": "../.babelrc",
"plugins": [
["react-docgen", {}, "app-react-docgen"]
]
}
Awesome sauce! The error disappeared! I went to check out the docs again and was met with bitter disappointment as the “No props found for this component” was back where the prop definitions should be. 😓
System: Environment Info:
System: OS: macOS 10.15.2 CPU: (12) x64 Intel® Core™ i7-8750H CPU @ 2.20GHz Binaries: Node: 10.18.0 - ~/.nvm/versions/node/v10.18.0/bin/node npm: 6.13.4 - ~/.nvm/versions/node/v10.18.0/bin/npm Browsers: Chrome: 79.0.3945.117 Firefox: 67.0.3 Safari: 13.0.4 npmPackages: @storybook/addon-a11y: ^5.3.0-rc.12 => 5.3.0-rc.12 @storybook/addon-actions: ^5.3.0-rc.12 => 5.3.0-rc.12 @storybook/addon-docs: ^5.3.0-rc.12 => 5.3.0-rc.12 @storybook/addon-links: ^5.3.0-rc.12 => 5.3.0-rc.12 @storybook/addon-storysource: ^5.3.0-rc.12 => 5.3.0-rc.12 @storybook/addons: ^5.3.0-rc.12 => 5.3.0-rc.12 @storybook/react: ^5.3.0-rc.12 => 5.3.0-rc.12 @storybook/source-loader: ^5.3.0-rc.12 => 5.3.0-rc.12
Issue Analytics
- State:
- Created 4 years ago
- Reactions:9
- Comments:9 (1 by maintainers)
Top GitHub Comments
Really? Seems like labels are being used effectively, and this is clearly a valid issue. I feel like stalebot should keep it’s grimy hands off issues that have been labeled by maintainers… 😏
So we’re encouraging dupes here, eh? Boo. 😒
Hey there, it’s me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!