Storybook: Addon-docs: `Identifier 'React' has already been declared` when using custom webpack config

Created on 21 Feb 2020  ·  14Comments  ·  Source: storybookjs/storybook

Describe the bug
I need to use a custom webpack config to load my .tsx files in my project. I added the correct loaders to handle Storybook addon-docs using .mdx files. I may missed something but when Storybook starts I get the current error:

Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /Users/Dev/Projects/issue_addondocs/src/components/Pill/stories/Pill.story.mdx: Identifier 'React' has already been declared (8:7)

   6 | import { assertIsFn, AddContext } from "@storybook/addon-docs/blocks";
   7 | 
>  8 | import React from 'react';
     |        ^
   9 | import { mdx } from '@mdx-js/react';
  10 | /* @jsx mdx */
  11 | import { assertIsFn, AddContext } from "@storybook/addon-docs/blocks";
    at Object.raise (/Users//Dev/Projects/issue_addondocs/node_modules/@babel/parser/lib/index.js:7017:17)
...

NB: I don't have react import in the story, only in my component file.

To Reproduce
I put a minimal version of my code settings which reproduce the issue on https://github.com/CPatchane/issue_addondocs

Steps to reproduce the behavior:

  1. Pull https://github.com/CPatchane/issue_addondocs and install dependencies (run yarn)
  2. Run yarn storybook

Expected behavior
Storybook should starts and display the stories correctly without errors.

NB: Using react-scripts and the CRA preset is not a solution for my use case, I need some custom webpack loaders that I removed from the https://github.com/CPatchane/issue_addondocs repo to keep it as simple as possible to debug.

System:
OS: macOS 10.15.3
CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
Binaries:
Node: 12.5.0 - ~/.nodenv/versions/12.5.0/bin/node
Yarn: 1.22.0 - /usr/local/bin/yarn
npm: 6.9.0 - ~/.nodenv/versions/12.5.0/bin/npm
Browsers:
Chrome: 80.0.3987.116
Safari: 13.0.5
npmPackages:
@storybook/addon-docs: ^5.3.13 => 5.3.13
@storybook/addons: ^5.3.13 => 5.3.13
@storybook/react: ^5.3.13 => 5.3.13
@storybook/source-loader: ^5.3.13 => 5.3.13

docs babel / webpack has workaround inactive needs reproduction question / support

All 14 comments

Do you have some kind of loader that automatically inserts a React import? Because the MDX compiler also inserts a React import. If they both do, then one of them is redundant.

Interesting 🤔
But I tried to remove some loaders but I get either this issue or the React is not defined issue :/
Here is the list of loaders I got from --debug-webpack using this repo (I put some comments about my tests) :

  module: {
    rules: [
      {
        test: /\.(mjs|jsx?)$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: '/Users/Dev/Projects/issue_addondocs/node_modules/.cache/storybook',
              presets: [
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-env/lib/index.js',
                  {
                    shippedProposals: true,
                    useBuiltIns: 'usage',
                    corejs: '3'
                  }
                ],
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-react/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-flow/lib/index.js'
              ],
              plugins: [
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-emotion/dist/babel-plugin-emotion.cjs.js',
                  { sourceMap: true, autoLabel: true }
                ],
                '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-macros/dist/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-transform-react-constant-elements/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-add-react-displayname/index.js',
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-react-docgen/lib/index.js',
                  {
                    DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES'
                  }
                ]
              ]
            }
          }
        ],
        include: [ '/Users/Dev/Projects/issue_addondocs' ],
        exclude: [
          '/Users/Dev/Projects/issue_addondocs/node_modules'
        ]
      },
      {
        test: /\.md$/,
        use: [
          {
            loader: '/Users/Dev/Projects/issue_addondocs/node_modules/@storybook/core/node_modules/raw-loader/dist/cjs.js'
          }
        ]
      },
      {
        test: /\.js$/,
        include: /node_modules\/acorn-jsx/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-env/lib/index.js',
                  { modules: 'commonjs' }
                ]
              ]
            }
          }
        ]
      },
      // Removing this get me `React is not defined`
      {
        test: /\.(stories|story).mdx$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: '/Users/Dev/Projects/issue_addondocs/node_modules/.cache/storybook',
              presets: [
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-env/lib/index.js',
                  {
                    shippedProposals: true,
                    useBuiltIns: 'usage',
                    corejs: '3'
                  }
                ],
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-react/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-flow/lib/index.js'
              ],
              plugins: [
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-emotion/dist/babel-plugin-emotion.cjs.js',
                  { sourceMap: true, autoLabel: true }
                ],
                '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-macros/dist/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-transform-react-constant-elements/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-add-react-displayname/index.js',
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-react-docgen/lib/index.js',
                  {
                    DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES'
                  }
                ]
              ]
            }
          },
          {
            loader: '@mdx-js/loader',
            options: {
              compilers: [ [Function: compiler] ],
              remarkPlugins: [ [Function: slug], [Function: externalLinks] ]
            }
          }
        ]
      },
      // Removing this loader changes nothing about this issue
      {
        test: /\.mdx$/,
        exclude: /\.(stories|story).mdx$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: '/Users/Dev/Projects/issue_addondocs/node_modules/.cache/storybook',
              presets: [
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-env/lib/index.js',
                  {
                    shippedProposals: true,
                    useBuiltIns: 'usage',
                    corejs: '3'
                  }
                ],
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-react/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/preset-flow/lib/index.js'
              ],
              plugins: [
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-emotion/dist/babel-plugin-emotion.cjs.js',
                  { sourceMap: true, autoLabel: true }
                ],
                '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-macros/dist/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/@babel/plugin-transform-react-constant-elements/lib/index.js',
                '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-add-react-displayname/index.js',
                [
                  '/Users/Dev/Projects/issue_addondocs/node_modules/babel-plugin-react-docgen/lib/index.js',
                  {
                    DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES'
                  }
                ]
              ]
            }
          },
          {
            loader: '@mdx-js/loader',
            options: {
              remarkPlugins: [ [Function: slug], [Function: externalLinks] ]
            }
          }
        ]
      },
      {
        test: /\.css$/,
        sideEffects: true,
        use: [
          '/Users/Dev/Projects/issue_addondocs/node_modules/style-loader/dist/cjs.js',
          {
            loader: '/Users/Dev/Projects/issue_addondocs/node_modules/css-loader/dist/cjs.js',
            options: { importLoaders: 1 }
          },
          {
            loader: '/Users/Dev/Projects/issue_addondocs/node_modules/postcss-loader/src/index.js',
            options: {
              ident: 'postcss',
              postcss: {},
              plugins: [Function: plugins]
            }
          }
        ]
      },
      {
        test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/,
        loader: '/Users/Dev/Projects/issue_addondocs/node_modules/file-loader/dist/cjs.js',
        query: { name: 'static/media/[name].[hash:8].[ext]' }
      },
      {
        test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
        loader: '/Users/Dev/Projects/issue_addondocs/node_modules/url-loader/dist/cjs.js',
        query: { limit: 10000, name: 'static/media/[name].[hash:8].[ext]' }
      },
      {
        test: /\.tsx?$/,
        use: [
          '/Users/Dev/Projects/issue_addondocs/node_modules/babel-loader/lib/index.js',
          {
            loader: '/Users/Dev/Projects/issue_addondocs/node_modules/ts-loader/index.js',
            options: { compilerOptions: { noEmit: false } }
          },
          '/Users/Dev/Projects/issue_addondocs/node_modules/react-docgen-typescript-loader/dist/index.js'
        ],
        exclude: /node_modules/
      },
      // Removing this get me also `React is not defined`
      {
        test: /\.story\.mdx$/,
        use: [
          '/Users/Dev/Projects/issue_addondocs/node_modules/babel-loader/lib/index.js',
          {
            loader: '@mdx-js/loader',
            options: { compilers: [ [Function: compiler] ] }
          }
        ]
      },
      {
        test: /\.story\.tsx?$/,
        loader: '/Users/Dev/Projects/issue_addondocs/node_modules/@storybook/source-loader/dist/server/index.js',
        exclude: [ /node_modules/ ],
        enforce: 'pre'
      }
    ]
  }

BTW do you have a working example of using addon-docs with Typescript or a custom webpack config not using CRA?

@CPatchane sure. we have a bunch of examples in the monorepo. official-storybook is not CRA and contains a bunch of typescript components

https://github.com/storybookjs/storybook/tree/next/examples/official-storybook

@shilman Thanks 👍

I may forgot to mention it but my issue here is about MDX files usage for stories, I don't find a component story using MDX in the official-storybook repo (the intro one is not a component story).

@CPatchane what do you mean by component story? There are a bunch of MDX use cases in there

@shilman Oh thanks, my bad I didn't search correctly 🤦‍♂️

Ok so I tried to copy the same main.js from the official-storybook (without babel config) and I used the Button from the example and I got this error:
Screenshot 2020-02-26 at 09 45 53

So it might not be webpack related here, it may be related to the babel config? Which seems to be the only difference here.
I updated the test repo btw.

Good news, after a lot of search and tests, I finally found a fix to my issues here \o/

First issue, about the Identifier 'React' has already been declared. I had to remove the custom mdx-loader I was adding in my custom webpack config (./customWebpack.config.js) since it's redundant with a loader added by storybook/addon-docs:

-   config.module.rules.push({
-     // 2a. Load `.stories.mdx` / `.story.mdx` files as CSF and generate
-     //     the docs page from the markdown
-     test: /\.story\.mdx$/,
-     use: [
-       require.resolve("babel-loader"),
-       {
-         loader: "@mdx-js/loader",
-         options: {
-           compilers: [createCompiler({})],
-         },
-       },
-     ],
-   })

Then I have to add TS extensions by doing config.resolve.extensions.push(".ts", ".tsx") in my config to get webpack resolving my files correctly.

Finally, I got the React is not defined error because I had that line in my .storybook/preview.js:

addDecorator(story => <div style={{ padding: 12 }}>{story()}</div>)

And that line needs obviously React to work correctly but it was quite impossible to know that the problem was from that file by just reading the stacktrace here :o. So adding the React import in this .storybook/preview.js file fixes this last issue.

My MDX story is now working correctly, I updated the issue repo to have the fix.

So I think the issue is resolved (maybe it could help documentation?), except if you have some better solutions/fixes to provide here :)

Thanks a lot @shilman 👍
BTW this addon-docs is such a great feature for Storybook, very nice work 🎉

Great to hear you got ti fixed, and thanks for the encouragement on Docs!!!

I'm working on the documentation and I'll take this use case in mind when I refresh. When SB docs launched it was fully manual config. Over time that became increasingly automated with the preset. Now the preset is the recommended way, but there may be manual config remnants that are confusing. I will make those two more clearly separated in the overhaul.

Hello, I was facing same issue as @CPatchane, tho I got something more:

Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: /Users/maciejkaczorowski/Sites/ergonode-git/frontend/stories/test.stories.mdx: This API has been removed. If you're looking for this functionality in Babel 7, you should import the '@babel/helper-module-imports' module and use the functions exposed  from that module, such as 'addNamed' or 'addDefault'.
    at File.addImport (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/core/lib/transformation/file/file.js:175:11)
    at PluginPass.addImport (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/core/lib/transformation/plugin-pass.js:35:22)
    at buildOpeningElementAttributes (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/babel-plugin-transform-vue-jsx/index.js:193:25)
    at buildElementCall (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/babel-plugin-transform-vue-jsx/index.js:130:17)
    at PluginPass.exit (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/babel-plugin-transform-vue-jsx/index.js:30:26)
    at newFn (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/visitors.js:179:21)
    at NodePath._call (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/path/context.js:55:20)
    at NodePath.call (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/path/context.js:42:17)
    at NodePath.visit (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/path/context.js:99:8)
    at TraversalContext.visitQueue (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitSingle (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/context.js:84:19)
    at TraversalContext.visit (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/context.js:140:19)
    at Function.traverse.node (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/index.js:84:17)
    at NodePath.visit (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/path/context.js:97:18)
    at TraversalContext.visitQueue (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitMultiple (/Users/maciejkaczorowski/Sites/ergonode-git/frontend/node_modules/@babel/traverse/lib/context.js:79:17)

main.js

const path = require("path");

module.exports = {
    stories: ['../stories/*.stories.(js|mdx)'],
    webpackFinal: async config => {
        config.module.rules = config.module.rules.filter(rule => !rule.test.test(".scss"));
        config.resolve.alias = {
            ...config.resolve.alias,
            ['@Core']: path.resolve(__dirname, '../modules/@ergo/core'),
        };

        config.module.rules.push({
            test: /\.scss$/,
            loaders: [
                'style-loader',
                'css-loader',
                'sass-loader',
                {
                    loader: 'sass-resources-loader',
                    options: {
                        resources: path.resolve(__dirname, '../modules/@ergo/core/assets/scss/main.scss')
                    }
                }
            ],
            include: path.resolve(__dirname, '../'),
        });

        config.module.rules.push({
            test: /\.story\.tsx?$/,
            loader: require.resolve("@storybook/source-loader"),
            exclude: [/node_modules/],
            enforce: "pre",
        });

        return config
    },
    addons: [
        {
            name: "@storybook/addon-docs",
            options: {
                configureJSX: false,
                sourceLoaderOptions: null,
            },
        },
        '@storybook/addon-actions',
        '@storybook/addon-knobs',
        '@storybook/addon-notes',
    ],
};

preview.js

import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks';
import { addParameters } from '@storybook/vue';
import Vue from 'vue';
import Button from '@Core/components/Buttons/Button';
import IconAdd from '@Core/components/Icons/Actions/IconAdd';

Vue.component('Button', Button);
Vue.component('IconAdd', IconAdd);

addParameters({
    docs: {
        container: DocsContainer,
        page: DocsPage,
    },
});

I've already spent too many hours on configuring mdx files with Storybook. I've found many configurations and each one has other issue. Could we get any tips how we should configure it?

cc @Aaron-Pool on MDX setup for Vue

@derpdead this looks like a different issue to me, and should probably be addressed elsewhere. If you could set up a reproduction repo and then ping me on Vue channel of the storybook discord I should be able to help you get that sorted out.

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ilyaulyanov picture ilyaulyanov  ·  100Comments

maraisr picture maraisr  ·  119Comments

firaskrichi picture firaskrichi  ·  61Comments

moimikey picture moimikey  ·  67Comments

Olian04 picture Olian04  ·  78Comments