storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.06k stars 9.24k forks source link

Unable to use Storybook as expected in a monorepo #5949

Closed maecapozzi closed 4 years ago

maecapozzi commented 5 years ago

Describe the bug I am working in a lerna-managed monorepo with Typescript. Originally, we had a separate storybook configuration in each package, which worked nicely. We decided we wanted a root-level storybook that pulled from the *.stories.tsx files inside each package.

Here is an example of the desired file structure:

root
.storybook
packages
  +-- package1
    +-- Button.stories.tsx
  +-- package2
    +-- FancyButton.stories.tsx

After following the fix in this issue to solve our original exports not found error, we had no more error messages, but also no stories appeared.

After digging into the devtools for some time, we found that the stories were being read, and the correct paths were being generated. It looked like at some point they were unexpectedly cleared from the StoryStore.

Is this expected behavior? Is it possible to create a top-level storybook that reads from stories inside of packages in a lerna-managed monorepo?

Expected behavior I expected to see a working storybook with stories from all of my packages in it.

Code snippets

webpack.config.js

module.exports = (baseConfig, env, config) => {
  // There is a bug in storybook for monorepo users.
  // Lines 5 - 12 are a temporary fix for this problem found in this issue:
  // https://github.com/storybooks/storybook/issues/3346#issuecomment-425516669
  config.module.rules = config.module.rules.filter(
    rule =>
      !(
        rule.use &&
        rule.use.length &&
        rule.use.find(({ loader }) => loader === 'babel-loader')
      )
  );
  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    loader: require.resolve('babel-loader'),
    options: {
      presets: [
        [
          'react-app',
          {
            flow: false,
            typescript: true,
          },
        ],
      ],
    },
  });
  config.resolve.extensions.push('.ts', '.tsx');
  return config;
};

config.ts

import { configure } from '@storybook/react';
// automatically import all files ending in *.stories.tsx
const req = require.context('../packages', true, /.stories.tsx$/);

function loadStories() {
  req.keys().forEach(req);
}

configure(loadStories, module);

System:

Additional context I ended up just creating a top-level /stories folder and moving all of my packages into it. That works nicely. I'd just like to understand why the structure I was originally aiming for doesn't work.

maecapozzi commented 5 years ago

@shilman, if possible, you might consider adding a lerna tag to this as well. I have a hunch that this problem is more lerna-related than typescript-related.

shilman commented 5 years ago

We don't have a lerna tag -- compatibility with other tools is our catchall. If I see a lot more lerna-related issues I'll def create one.

tmeasday commented 5 years ago

Hi @maecapozzi - I'm glad you figured out a workaround, but I'm wondering about the original issue. I wonder why you think it might be lerna related? Because of symlinks within node_modules? I would expect SB to just ignore node_modules when searching for stories, but I could be missing something.

OTOH maybe there is a more general issue with monorepos specifically with typescript? I know plenty of people (myself) included have a similar setup to what you originally described so there must be something different going on here.

tmeasday commented 5 years ago

Sorry I should add I guess what I did to work around #3346 is:

  const babelLoader = storybookBaseConfig.module.rules[0];
  babelLoader.exclude.push(
    path.resolve('./lib/components/node_modules'),
    /* etc */
  );

Which is perhaps a little simpler and less disruptive that what you posted...

shilman commented 5 years ago

Related: https://github.com/storybooks/storybook/issues/5220

maecapozzi commented 5 years ago

@tmeasday, I did think that maybe it had to do with the symlinks.

Alternatively, as I was digging into the dev tools, it looked like something called StoryStore was getting constantly recreated as storybook went into different packages, and losing its context.

astrotim commented 5 years ago

I am also unable to get SB5 working with our Lerna monorepo. We have a custom Webpack config which I haven't had any success updating to the single signature format. Initially it was blowing up on the .css files (we use PostCSS), and after some trial and error I progressed to it blowing up on the JSX parsing.

// webpack.config.js
module.exports = async ({ config, mode }) => {
  config.module.rules.push(babelLoader)
  config.module.rules.push(cssLoader)

  return config;
}

Storybook will run with above config if I only include a trivial example, however when I attempt to load a story with some of our monorepo components, I get a bunch of errors like:

Module parse failed: Unexpected token (13:6)
You may need an appropriate loader to handle this file type.

and

Module build failed (from ./node_modules/@storybook/core/node_modules/postcss-loader/src/index.js):
SyntaxError

(2:1) Unknown word

For comparison, my working SB4 custom Webpack config is

module.exports = storybookBaseConfig => {
  storybookBaseConfig.module.rules.push(babelLoader);
  storybookBaseConfig.module.rules.push(cssLoader);

  return storybookBaseConfig;
};
mr-wildcard commented 5 years ago

@astrotim I'm having the exact same issue right now in our monorepo (not using Lerna though).

I temporarily fixed it by prefixing the import statement this way :

import '!style-loader!css-loader!highlight.js/styles/github-gist.css';

I never used Lerna but I don't feel like this is related to it... It might have to do with what I'd call webpack contexts switching : the custom webpack configuration we provide to Storybook somehow conflicts with what Storybook does internally.

Don't know if it'll help, but you might have a look to webpack resolveLoader.modules : https://webpack.js.org/configuration/resolve/#resolveloader I kind of resolved some other painful issues with it.

astrotim commented 5 years ago

I actually now think my issue in unrelated to our monorepo environment, but my rather it is #6083

sibelius commented 5 years ago

I've got this error as well, any way to fix this or any workaround?

I've tried to include packages on our custom wepback config

config.module.rules[0].include = [path.join(cwd, 'src'), path.join(cwd, 'packages/')];

but it did not worked well

this is the error:

ReferenceError: exports is not defined
    at Module../packages/shared/dist/Valeu.js (MyEmail.story.tsx:41)
    at __webpack_require__ 
Centerworx commented 5 years ago

I am also having the same issue. My monorepo is just running yarn workspaces, no lerna. All of my packages are running typescript.

sibelius commented 5 years ago

Use latest alphas releases

mbulfair commented 5 years ago

I'm working with a monorepo as well, but the issue has something to do with css-loader, I am using style-loader/css-loader/postcss-loader with css modules, I'm trying to switch from styleguidst to storybook, and it hasn't been easy at all. I am not sure where the issue is but, I get the unknown word: var content = require("!!../../../node_modules/css-loader/dist/cjs.js??ref--10-1!../../../node_modules/postcss-loader/src/index.js??ref--10-2!./button.module.css");

Using the beta.0 version of 5.1 as I needed the core-js v3 issue resolved.

ux-engineer commented 5 years ago

Just noticed this import is not working when using in a Lerna monorepository import '@fortawesome/fontawesome-svg-core/styles.css';. When copied @fortawesome folder inside storybook folder's node_modules folder, the import started working (although can't get FA icons to show up yet)...

Jimmydalecleveland commented 5 years ago

Hello, I'm using a monorepo of gatsby projects (gatsby-themes) and getting this error, only when importing Link from gatsby, no matter what I try:

ERROR in my-gatsby/node_modules/gatsby/cache-dir/gatsby-browser-entry.js 17:2
Module parse failed: Unexpected token (17:2)
You may need an appropriate loader to handle this file type.
| 
| const StaticQuery = props => (
>   <StaticQueryContext.Consumer>
|     {staticQueryData => {
|       if (
 @ ./src/baseComponents/Link/Link.stories.jsx 4:0-30
 @ . sync \.stories\.(js|jsx)$
 @ ./.storybook/config.js
 @ multi my-gatsby/node_modules/@storybook/core/dist/server/common/polyfills.js /my-gatsby/node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/config.js (webpack)-hot-middleware/client.js?reload=true

I feel certain this is an issue with monorepos and storybook (perhaps the combination with gatsby as well), because I have a gatsby starter project running just fine with storybook ( gatsby: 2.8.4 and @storybook/react: 5.1.3) after following this tutorial: https://www.gatsbyjs.org/docs/visual-testing-with-storybook/

I took that working gatsby starter and placed it in my monorepo, but not in a directory that uses yarn workspaces, and it also runs just fine. It only causes the error shown above when placed under a folder that uses yarn workspaces which handles node_modules at the root of the project.

I've tried adding a custom .storybook/.babelrc file, loading in the presets for env and react as well, but no luck there either.

ndelangen commented 5 years ago

@Jimmydalecleveland run storybook with the --debug-webpack flag and it will print the webpack config for you.

Look at the loaders defined and you'll see there are exclude & include rules for the loaders responsible for transpiling code.

I think if you just remove the include property, it should start to work for you.

Jimmydalecleveland commented 5 years ago

@ndelangen Thank you for the quick response. I solved this problem last night differently, and now that I've tried your suggestion and it also works, I'm not understanding why.

I pushed a separate include rule: path.resolve('../../node_modules/gatsby') because my understanding was that Gatsby has un-transpiled ES6 code and I saw from the Error I previously posted that it was failing when encountering JSX in my project's root /node_modules/gatsby. That worked, but I'm not sure why your suggestion works, since it is removing the include for the inner yarn workspace package. If you don't mind, could you explain that a bit?

If you need more context, here is the before and after log of what that config looks like after applying your suggestion:

// before deleting include rule
{
  test: /\.(mjs|jsx?)$/,
  use: [ { loader: 'babel-loader', options: [Object] } ],
  include: [ './my-project/themes/gatsby-theme-storybook' ],
  exclude: [ './my-project/themes/gatsby-theme-storybook/node_modules' ]
}

// after
{
  test: /\.(mjs|jsx?)$/,
  use: [ { loader: 'babel-loader', options: [Object] } ],
  exclude: [ './my-project/themes/gatsby-theme-storybook/node_modules' ]
}

And this is the line I was previously using that worked in ./my-project/themes/gatsby-theme-storybook/.storybook/webpack.config.js: config.module.rules[0].include.push(path.resolve('../../node_modules/gatsby'))

Thanks again, I really appreciate it.

ndelangen commented 5 years ago

@Jimmydalecleveland removing that include is on my todo list, but I'm afraid of it messing up people's setup, So I want to do it for the next major (6.0) I think.

My solution works because it simply removes all include filters.

Yours work, because... I have no freaking clue why. 😭 not enough context on the project file structure to really judge.

Jimmydalecleveland commented 5 years ago

@ndelangen Ok, no problem. I'm pretty sure it is a very specific problem to monorepos with Gatsby and storybook not at the root of the project. Take care!

hueter commented 5 years ago

thanks @Jimmydalecleveland, your fix worked for me! I also have a gatsby app inside a monorepo with yarn workspaces and kept getting an ambiguous error from nodemodules/gatsby when running yarn storybook

DmitryEfimenko commented 4 years ago

this should not be closed. This issue will only be more important with the rise of Nrwl NX

ndelangen commented 4 years ago

8822 https://github.com/storybookjs/storybook/pull/8822/commits/288cb501ab2f40536addf1365d1abb7886179c6e

ndelangen commented 4 years ago

PR is open addressing this, will be a 6.0.0 feature

claudio-moya commented 4 years ago

I also report this issue, when I want to load packages or files outside of node_modules I got the empty "exports" issue, in my case is like this:

.storybook/
  ...
  webpack.config.js
npm/
  my-custom-package/
     index.js    
     ...
src/
  ...
webpack.config.js

I solved patching the .storybook/webpack.config.js using @i-like-robots solution:

https://github.com/storybookjs/storybook/issues/3346#issuecomment-554270012

shilman commented 4 years ago

Whoopee!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.0.0-alpha.0 containing PR #8822 that references this issue. Upgrade today to try it out!

You can find this prerelease on the @next NPM tag.

Closing this issue. Please re-open if you think there's still more to do.

kvedantmahajan commented 3 years ago

This is important. "@storybook/react": "^6.3.4", doesn't have it. Here is the main file. Only stories at root folder works and not inside any of packages/**

module.exports = {
  stories: [
    '../packages/**/*.stories.mdx',
    '../packages/**/*.stories.@(js|jsx|ts|tsx)'
  ],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials']
}

@shilman This is closed. Not sure why. What would be the workaround?

@claudio-moya Could you please post your patch?