Gatsby: Module not found: Error: Can't resolve 'components' using Storybook.

Created on 16 Jul 2020  路  8Comments  路  Source: gatsbyjs/gatsby

Description

Hi, I just installed Storybook on my existing Gatsby application. The installation was successful. I can access to the Storybook stories examples in http://localhost:6006. Gatsby develop/build works fine.

I followed tutorial for webpack config : https://www.gatsbyjs.org/docs/visual-testing-with-storybook/ but still have errors.

But when I tried to use my own components I have errors :

ERROR in ./src/2-Button.stories.js
Module not found: Error: Can't resolve 'components' in '/Users/xxx/front/src'
 @ ./src/2-Button.stories.js 4:0-36 7:13-19 10:29-35 22:29-35
 @ ./src sync ^\.\/(?:(?:(?!\.)(?:(?:(?!(?:|\/)\.).)*?)\/)?(?!\.)(?=.)[^\/]*?\.stories\.js\/?)$
 @ ./.storybook/generated-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/generated-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=true

Here is the content of the file : 2-Button.stories.js

import React from 'react';
import {action} from '@storybook/addon-actions';
import {Button} from 'components';

export default {
  title: 'Hello3',
  component: Button,
};

export const Text = () => (
  <Button onClick={action('clicked')}>Hello Button</Button>
);

I think the thing is that I use this code below in my gatsby-node.js, but I'm not sure if it's because of that.
The idea is to keep this code because everything is based on this. So I can import {MyCustomButton} from 'components';

/* Allow us to use something like: import { X } from 'directory' instead of '../../folder/directory' */
exports.onCreateWebpackConfig = ({ actions }) => {
  actions.setWebpackConfig({
    resolve: {
      modules: [path.resolve(__dirname, 'src'), 'node_modules'],
    },
  });
};

I tried to update ./storybook/main.js by add some custom configurations to fix that but doesn't work...

How can I fix that please?

Steps to reproduce

yarn storybook

Expected result

No errors.

Actual result

What happened.

ERROR in ./stories/2-Button.stories.js
Module not found: Error: Can't resolve 'components' in '/Users/xxx/xxx/front/stories'
 @ ./stories/2-Button.stories.js 4:0-36 7:13-19 10:29-35 15:29-35
 @ ./stories sync ^\.\/(?:(?:(?!\.)(?:(?:(?!(?:|\/)\.).)*?)\/)?(?!\.)(?=.)[^\/]*?\.stories\.js\/?)$
 @ ./.storybook/generated-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/preview.js ./.storybook/generated-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=true

Environment

gatsby info --clipboard

  System:
    OS: macOS 10.14.5
    CPU: (8) x64 Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 10.16.0 - /usr/local/opt/node@10/bin/node
    Yarn: 1.19.2 - ~/.yarn/bin/yarn
    npm: 6.9.0 - /usr/local/opt/node@10/bin/npm
  Languages:
    Python: 2.7.10 - /usr/bin/python
  Browsers:
    Firefox: 78.0.2
    Safari: 13.1.1
  npmPackages:
    gatsby: ^2.0.0 => 2.15.24 
    gatsby-cli: ^2.4.16 => 2.7.50 
    gatsby-image: ^2.0.26 => 2.2.21 
    gatsby-plugin-emotion: ^4.0.1 => 4.1.7 
    gatsby-plugin-google-tagmanager: ^2.1.4 => 2.1.10 
    gatsby-plugin-manifest: ^2.2.13 => 2.2.18 
    gatsby-plugin-mdx: ^1.0.44 => 1.0.44 
    gatsby-plugin-netlify: ^2.0.12 => 2.1.15 
    gatsby-plugin-react-helmet: ^3.0.0 => 3.1.8 
    gatsby-plugin-sharp: ^2.0.17 => 2.2.25 
    gatsby-plugin-sitemap: ^2.2.3 => 2.2.14 
    gatsby-source-filesystem: ^2.0.12 => 2.1.26 
    gatsby-transformer-sharp: ^2.1.10 => 2.2.17 
  npmGlobalPackages:
    gatsby-cli: 2.4.8
awaiting author response

Most helpful comment

OH !!! Finally works !!!! Thank you @ascorbic !!!

I added your code in main.js

Here is the result

const path = require('path');

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links'],
  webpackFinal: async (config) => {
    // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
    config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/];

    // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
    config.module.rules[0].use[0].loader = require.resolve('babel-loader');

    // use @babel/preset-react for JSX and env (instead of staged presets)
    config.module.rules[0].use[0].options.presets = [
      require.resolve('@babel/preset-react'),
      require.resolve('@babel/preset-env'),
    ];

    config.module.rules[0].use[0].options.plugins = [
      // use @babel/plugin-proposal-class-properties for class arrow functions
      require.resolve('@babel/plugin-proposal-class-properties'),
      // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
      require.resolve('babel-plugin-remove-graphql-queries'),
    ];

    // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
    config.resolve.mainFields = ['browser', 'module', 'main'];

    // @ascorbic's fix
    config.resolve.modules = [
      path.resolve(__dirname, '..', 'src'),
      path.resolve(__dirname, '..', 'node_modules'),
    ];

    return config;
  },
};

All 8 comments

Hi. You are right that this is related to your custom webpack config. This problem is that Storybook doesn't use Gatsby's webpack config, so your resolution rule is ignored. You either need to use a custom webpack config in Storybook, or (simpler) do a regular import for the component in the stories: import { Button } from "../path/to/your/button/file". Let me knoiw if that fixes it.

@ascorbic Thanks for you answer.

My ./storybook/main.js contains this code below (I followed the Gatsby + Storybook tutorial : https://www.gatsbyjs.org/docs/visual-testing-with-storybook)

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links'],
  webpackFinal: async (config) => {
    // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
    config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/];

    // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
    config.module.rules[0].use[0].loader = require.resolve('babel-loader');

    // use @babel/preset-react for JSX and env (instead of staged presets)
    config.module.rules[0].use[0].options.presets = [
      require.resolve('@babel/preset-react'),
      require.resolve('@babel/preset-env'),
    ];

    config.module.rules[0].use[0].options.plugins = [
      // use @babel/plugin-proposal-class-properties for class arrow functions
      require.resolve('@babel/plugin-proposal-class-properties'),
      // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
      require.resolve('babel-plugin-remove-graphql-queries'),
    ];

    // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
    config.resolve.mainFields = ['browser', 'module', 'main'];

    return config;
  },
};

When I try you solution, the component is found (great) but all imports inside of it are not resolved.

ERROR in ./src/components/Button.js
Module not found: Error: Can't resolve 'helpers' in '/Users/xxx/xxx/src/components'
 @ ./src/components/Button.js 184:0-36 190:97-106 190:138-147 190:159-168 190:620-629 190:641-650 190:802-811 190:829-838 190:920-929 246:52-61
 @ ./stories/2-Button.stories.js
 @ ./stories sync ^\.\/(?:(?:(?!\.)(?:(?:(?!(?:|\/)\.).)*?)\/)?(?!\.)(?=.)[^\/]*?\.stories\.js\/?)$
 @ ./.storybook/generated-entry.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/preview.js ./.storybook/generated-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=true
| ./storybook
| src
   | components
       | Buttons.js
   | helpers
   | pages
| stories
   | 2-Button.stories.js

Is there a way to force Storybook to use the same thing like this code ?

exports.onCreateWebpackConfig = ({ actions }) => {
  actions.setWebpackConfig({
    resolve: {
      modules: [path.resolve(__dirname, 'src'), 'node_modules'],
    },
  });
};

OK, to force it to use that, try something like"

config.resolve.modules = [path.resolve(__dirname, '..',  'src'), path.resolve(__dirname, '..',  'node_modules')]

Your original code also had an error. Instead of:

import {Button} from 'components';

...it should be

import {Button} from 'components/Buttons';

You don't have an index file in components, so it wouldn't know where to look for it.

In my opinion though, your custom webpack config is not a great idea, and is the source of all of these problems. It will also mean that you can't use any node module that matches the name of one of your directories. If you switch them all to using relative imports then this won't be a problem.

Sorry, yes I have an index.js

| ./storybook
| src
   | components
       | Buttons.js
       | index.js
   | helpers
       | index.js
   | pages
       | ... .js
       | index.js
| stories
   | 2-Button.stories.js

That's why I used directly components instead components/Button

OH !!! Finally works !!!! Thank you @ascorbic !!!

I added your code in main.js

Here is the result

const path = require('path');

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-actions', '@storybook/addon-links'],
  webpackFinal: async (config) => {
    // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
    config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/];

    // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
    config.module.rules[0].use[0].loader = require.resolve('babel-loader');

    // use @babel/preset-react for JSX and env (instead of staged presets)
    config.module.rules[0].use[0].options.presets = [
      require.resolve('@babel/preset-react'),
      require.resolve('@babel/preset-env'),
    ];

    config.module.rules[0].use[0].options.plugins = [
      // use @babel/plugin-proposal-class-properties for class arrow functions
      require.resolve('@babel/plugin-proposal-class-properties'),
      // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
      require.resolve('babel-plugin-remove-graphql-queries'),
    ];

    // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
    config.resolve.mainFields = ['browser', 'module', 'main'];

    // @ascorbic's fix
    config.resolve.modules = [
      path.resolve(__dirname, '..', 'src'),
      path.resolve(__dirname, '..', 'node_modules'),
    ];

    return config;
  },
};

@ascorbic Now I just have another problem about styling.

My component Button has font styles inherit from my App.

Is it possible to import global styling to set style context ?

Yes, you should import those styles into the storybook config in the same way that you import them into your app

Okay, thanks!
Yeah, I found that I can use decorators : https://storybook.js.org/docs/addons/introduction/#storybook-decorators

Perfect ! I'm go to go now!

Was this page helpful?
0 / 5 - 0 ratings