How to configure Storybook to run from a directory other than the project root
Asked Answered
C

2

8

I'm trying to configure Storybook to run from a directory that is not the root of the project and I'm having a little trouble. I've setup a mono-rep using https://github.com/jibin2706/cra-monorepo-demo as base.

My project directory looks like this:

- project
-- packages
---- app
---- components
---- utils
---- stories
------ .storybook
-------- main.js
------ ComponentA
-------- ComponentA.stories.mdx

Because I'm using a monorep with aliases (e.g. a component can import from @project/utils) I've configured webpack in .storybook/main.js to read like:

const path = require('path');

module.exports = {
  stories: ['../**/*.stories.mdx', '../../**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/preset-create-react-app',
  ],
  webpackFinal: async (config, { configType }) => {
    const result = {
      ...config,
      resolve: {
        ...config.resolve,
        alias: {
          ...config.resolve.alias,
          '@project/components': path.resolve(
            process.cwd(),
            'packages/components'
          ),
        },
      },
    };
  },
};

Then within my ComponentA.stories.mdx I have an import like import { ComponentA } from '@project/components';

When I run this however, I'm always hitting an error when it encounters JSX within a .js file:

ERROR in ./packages/components/MyComponent1/MyComponent1.js 106:11 Module parse failed: Unexpected token (106:11) File was processed with these loaders:

  • ./node_modules/@pmmmwh/react-refresh-webpack-plugin/loader/index.js You may need an additional loader to handle the result of these loaders. |

return <React.Fragment>{children}</React.Fragment>;

I can't seem to work out why this error is throwing. I've tried running with yarn storybook --debug-webpack which seems to include a loader for both jsx and js files. I'm not 100% sure if this is correct, but it looks roughly right from other docs I've read.

module: {
    rules: [
      {
        test: /\.(mjs|tsx?|jsx?)$/,
        use: [
          {
            loader: '/home/ian/src/cra-monorepo-demo/node_modules/babel-loader/lib/index.js',
            options: {
              sourceType: 'unambiguous',
              presets: [
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-env/lib/index.js',
                  { shippedProposals: true, loose: true }
                ],
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-typescript/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-react/lib/index.js'
              ],
              plugins: [
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-shorthand-properties/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-block-scoping/lib/index.js',
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-decorators/lib/index.js',
                  { legacy: true }
                ],
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
                  { loose: true }
                ],
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-private-methods/lib/index.js',
                  { loose: true }
                ],
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-export-default-from/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
                  { loose: true, useBuiltIns: true }
                ],
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-classes/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-arrow-functions/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-parameters/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-destructuring/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-spread/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-for-of/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@storybook/core-common/node_modules/babel-plugin-macros/dist/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-optional-chaining/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-nullish-coalescing-operator/lib/index.js',
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/babel-plugin-polyfill-corejs3/lib/index.js',
                  {
                    method: 'usage-global',
                    absoluteImports: '/home/ian/src/cra-monorepo-demo/node_modules/core-js/index.js',
                    version: '3.16.1'
                  }
                ],
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-template-literals/lib/index.js'
              ]
            }
          }
        ],
        include: [ '/home/ian/src/cra-monorepo-demo' ],
        exclude: [ /node_modules/, /dist/ ]
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: '/home/ian/src/cra-monorepo-demo/node_modules/babel-loader/lib/index.js',
            options: {
              sourceType: 'unambiguous',
              presets: [
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-env/lib/index.js',
                  {
                    shippedProposals: true,
                    modules: false,
                    loose: true,
                    targets: 'defaults'
                  }
                ],
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/preset-react/lib/index.js'
              ],
              plugins: [
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-shorthand-properties/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-block-scoping/lib/index.js',
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-decorators/lib/index.js',
                  { legacy: true }
                ],
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-class-properties/lib/index.js',
                  { loose: true }
                ],
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-private-methods/lib/index.js',
                  { loose: true }
                ],
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-export-default-from/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-syntax-dynamic-import/lib/index.js',
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js',
                  { loose: true, useBuiltIns: true }
                ],
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-classes/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-arrow-functions/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-parameters/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-destructuring/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-spread/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-transform-for-of/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@storybook/core-common/node_modules/babel-plugin-macros/dist/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-optional-chaining/lib/index.js',
                '/home/ian/src/cra-monorepo-demo/node_modules/@babel/plugin-proposal-nullish-coalescing-operator/lib/index.js',
                [
                  '/home/ian/src/cra-monorepo-demo/node_modules/babel-plugin-polyfill-corejs3/lib/index.js',
                  {
                    method: 'usage-global',
                    absoluteImports: '/home/ian/src/cra-monorepo-demo/node_modules/core-js/index.js',
                    version: '3.16.1'
                  }
                ]
              ]
            }
          }
        ],
        include: [Function: include]
      },
...

Can anyone see what I might be missing here, or what additional config is required?

Cahilly answered 13/8, 2021 at 15:46 Comment(0)
F
2

The issue is probably with the Storybook project root. The default babel-loader defines an include that is equal to the project root. And the "project root" is usually the closest .git folder.

A workaround is to set the correct project root:

const path = require("path");

module.exports = {
  // ...

  webpackFinal: async (config, { configType }) => {
    const babelLoaderRule = config.module.rules.find(
      (rule) => rule.test.toString() === /\.(mjs|tsx?|jsx?)$/.toString()
    );
    // set correct project root
    babelLoaderRule.include = [path.resolve(__dirname, "../..")];

    return config;
  }
};

What "correct" path is, depends on your setup.

Check my post for a longer write-up.

Favian answered 29/12, 2021 at 16:14 Comment(0)
E
1

As far as I can tell your .storybook/main.js looks fine.

The built-in loader should also work as expected.

Concerning the error you're seeing: have you tried changing the file-type (aka renaming the file ending) from .js to .jsx? Because the loader can discern between .js and .jsx files, however the interpreter cannot comprehend jsx-notation if it's not explicitely told to do so (as is the case with your .js files).

Endure answered 23/8, 2021 at 10:18 Comment(3)
I'm going to reward you the bounty - I've not had a chance to confirm but as it's the only answer here and it's something I hadn't considered it's the best there is :)Cahilly
Thank you, I hope you get to solve your problem ASAPEndure
I tried changing just the single file to a .jsx to see if it moved the problem along but unfortunately it didn't :(Cahilly

© 2022 - 2024 — McMap. All rights reserved.