question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Problems specifying "react-docgen" plugin in custom .babelrc

See original GitHub issue

Describe 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:

  1. Ensure a component story is defined for a component that has propTypes defined
  2. 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)
  3. Create .storybook/.babelrc which extends from another and specifies "react-docgen" as an additional plugin (observe error in console)
  4. 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: Screen Shot 2020-01-10 at 12 57 59 PM

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:closed
  • Created 4 years ago
  • Reactions:9
  • Comments:9 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
Smolationscommented, May 15, 2020

I am going close this issue to help our maintainers focus on the current development roadmap instead.

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… 😏

If the issue mentioned is still a concern, please open a new ticket and mention this old one.

So we’re encouraging dupes here, eh? Boo. 😒

0reactions
stale[bot]commented, May 13, 2020

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!

Read more comments on GitHub >

github_iconTop Results From Across the Web

babel-plugin-react-docgen - npm package - Snyk
The npm package babel-plugin-react-docgen was scanned for known vulnerabilities and missing license, and no issues were found. Thus the package was deemed as ......
Read more >
gatsby-transformer-react-docgen - npm
Expose React component metadata and prop information as GraphQL types. Latest version: 8.3.0, last published: 8 days ago.
Read more >
babel-plugin-react-docgen | Yarn - Package Manager
You may use the 3 built-in react-docgen resolvers by specifying its name as a string , or you may specify a custom resolver...
Read more >
Getting Storybook react-docgen-typescript-loader to use ...
OMG this was the issue for me. Now I can specify this as an enhancement. – kamranicus. Sep 25, 2019 at 15:55.
Read more >
Setting up a custom .babelrc file without ejecting a React App ...
In this video we create a custom . babelrc file and configure a create react application to incoperate it into its build process....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found