storybook: [Bug]: Storybook 7 migration not sucessful in monorepo

Describe the bug

When migrating a Storybook project included in a monorepo setting, Storybook is broken and can’t start. I have seen this on about four projects, using yarn workspaces and turborepo as well.

The error relates to how Storybook libraries are (wrongly) hoisted. The error message most of the times is related to not finding a framework package:

image

Reason being that @storybook/core-server is hoisted at the root level, while @storybook/web-components it not hoisted and stays at a package level, therefore a call like require('@storybook/web-components') coming from core-server, fails and displays that error.

The fix normally is to either:

  • nuke lock files (e.g. yarn.lock) and rerun install
  • force install e.g. yarn install --force
  • add nohoist for Storybook libraries e.g.
"workspaces": {
  "nohoist": [
	  "**/@storybook/**",
      "**/storybook"
    ]
}

But neither of the solutions are optimal, as they can affect user’s code. The nohoist solution only works for package managers that support it, therefore projects that use tools like turborepo can’t use such fix.

To Reproduce

  • I’m in the process of getting a repro!

System

No response

Additional context

No response

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 19
  • Comments: 19 (3 by maintainers)

Most upvoted comments

Thanks, @adrianu197!

We are using yarn v1 and a lerna 6.5 monorepo.

My working .storybook/main.js:

import path from 'path';
const wrapForPnp = (packageName) =>
  path.dirname(require.resolve(path.join(packageName, 'package.json')));

const config = {
  core: {
    builder: 'webpack5',
  },
  framework: {
    name: wrapForPnp('@storybook/react-webpack5'),
    options: {},
  },
  stories: ['../stories/**/*.stories.@(js|mdx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    'storybook-dark-mode',
  ],
  docs: {
    autodocs: true,
  },
};

export default config;

Using pnpm in a monorepo I ran into this issue. Tweaking .npmrc config was no help. Adding "@storybook/react-webpack5": "~7.0.6" as a dev dependency to my root package.json fixed the issue. It’s not ideal but it works for now.

A temporary workaround for Yarn users is to add an override for the core package in your Yarn config.

In .yarnrc.yml add the following section:

packageExtensions:

    "@storybook/core-common@*":
        dependencies:
            "@storybook/react-webpack5": "7.0.3"

Replace @storybook/react-webpack5 by the missing module (and use the same version as your other Storybook dependencies)

I had the same issue(about Cannot find module '@storybook/react-webpack5/preset') and I solved it with: https://storybook.js.org/docs/react/faq#how-do-i-fix-module-resolution-while-using-pnpm-plug-n-play

Screenshot 2023-06-21 at 16 53 55

Same issue in another pnpm monorepo:

image

The fact that it’s happening in pnpm, yarn and npm monorepos does make it seem like there is something wrong in how storybook v7 is setup/specifying its dependencies.

@adrianu197 and @asyndesis solutions worked for me

Just adding I have been unable to get 7 to run in a pnpm monorepo. I have an .npmrc file with hoist=false in it. I removed @storybook/react from the root package.json so there shouldn’t be any hoisting happening. But I still get

WARN   Failed to load preset: "@storybook/react-webpack5/preset"
ERR! Error: Cannot find module '@storybook/react-webpack5/preset'

I tried swapping react-webpack5 for react-vite and got the exact same error but with @storybook/react-vite/preset.

All the pnp implementations intend to not allow packages to access any other package that isn’t specified as a dep in their package.json as an intentional part of their design…

So the problem would seem to be that while @storybook/react-webpack5 is a dep in the user’s application’s package.json, because it is not listed as a dep in @storybook/core-common the pnp implementations are not making it available to require() (This assumption is supported by @ekeijl 's fix working. Telling yarn that @storybook/core-common has the preset as a dep makes it magically available via pnp/symlink).

I think conceptually what would work is if rather than passing framework: { name: 'astringnameofamodule' } we had something more along the lines of framework: require('astringnameofmodule')

That is to say, @storybook/react-webpack5 would be available to import in .storybook/main.js because it’s listed as a dep in the storybook app’s package.json, but passing the module name as a string and letting core-common do the import is the cause of the issue…

Reason being that @storybook/core-server is hoisted at the root level, while @storybook/web-components it not hoisted and stays at a package level,

@yannbf To get more insight why this happens - why package manager has to come up with such hoisting decisions one can use NM_DEBUG_LEVEL=2 yarn with Yarn 2+ and node-modules linker on the problematic project - it will show why the package cannot be hoisted shallower.

Hi,

I have the same issue Cannot find module '@storybook/react-vite/preset' with rc-9 but it is working with rc-3 without modifying anything else

In my case, I am using yarn 3.5.0 workspaces and lerna. I was able to temporarily workaround the issue by adding

nmHoistingLimits: workspaces

to my monorepo’s .yarnrc.yml. I see this only as a temporary solution.