Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Using Storybook with Next@15 RC fails at header mocks #29380

Closed
terrymun opened this issue Oct 16, 2024 · 7 comments · Fixed by #29587
Closed

[Bug]: Using Storybook with Next@15 RC fails at header mocks #29380

terrymun opened this issue Oct 16, 2024 · 7 comments · Fixed by #29587

Comments

@terrymun
Copy link

terrymun commented Oct 16, 2024

Describe the bug

As Next.js RC for v15 has been released for testing, I'm investigating if it is possible to perform an upgrade of a Next.js app containing a storybook from next@14 to next@15-rc.1. When attempting to build a storybook (using storybook build), I encounter this error:

Module not found: Error: Can't resolve 'next/dist/client/components/headers' in '/REDACTED_PATH_TO_REPO_ROOT/node_modules/@storybook/nextjs/dist/export-mocks/headers'

I suspect this is likely due to the breaking changes made to the folder structure inside node_modules/next/dist. The release candidate no longer has the nested folder structure the @storybook/nextjs depends on.

This can be reproduced if any component consumed by Storybook invokes a server action in nextjs that uses the dynamic API, e.g. cookies() or headers():

'use server';

import { headers } from "next/headers";

export const dummyServerAction = async () => {
  // NOTE: This is the line that wiill causes Storybook to fail
  //       If you comment it out and replace with the line below, Storybook will work:
  //       const referrer = 'http://localhost:6006/';
  const referrer = (await headers()).get('referer');

  return {
    message: 'Server action was successful',
    referrer,
  }
}

Reproduction link

https://github.com/terrymun/nextjs15-storybook

Reproduction steps

Running storybook build with next@15 release candidate should not fail with the message:

Module not found: Error: Can't resolve 'next/dist/client/components/headers' in '/REDACTED_PATH_TO_REPO_ROOT/node_modules/@storybook/nextjs/dist/export-mocks/headers'

I am unfortunately unable to reproduce this with an example from storybook.new, but I can confirm that inspecting the code in @storybook/nextjs does uncover statements that points to a file for next@14, but not to a file in next@15-rc.1: https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/src/export-mocks/headers/index.ts#L3C1-L6C53

System

System:
  OS: macOS 14.7
  CPU: (10) arm64 Apple M1 Pro
  Shell: 5.9 - /bin/zsh
Binaries:
  Node: 20.17.0 - ~/.nvm/versions/node/v20.17.0/bin/node
  npm: 10.8.2 - ~/.nvm/versions/node/v20.17.0/bin/npm <----- active
  pnpm: 9.12.2 - ~/.nvm/versions/node/v20.17.0/bin/pnpm
Browsers:
  Chrome: 129.0.6668.101
  Edge: 129.0.2792.89
  Safari: 18.0

Additional context

No response

@robcaldecott
Copy link

Also trying Next.js 15 RC and get the following when attempting to run Storybook in dev mode.

=> Failed to build the preview
Error: Cannot find module 'ajv/dist/compile/codegen'
Require stack:
- ./node_modules/ajv-keywords/dist/definitions/typeof.js
- ./node_modules/ajv-keywords/dist/keywords/typeof.js
- ./node_modules/ajv-keywords/dist/keywords/index.js
- ./node_modules/ajv-keywords/dist/index.js
- ./node_modules/schema-utils/dist/validate.js
- ./node_modules/schema-utils/dist/index.js
- ./node_modules/webpack-dev-middleware/dist/index.js
- ./node_modules/@storybook/builder-webpack5/dist/index.js
- ./node_modules/@storybook/nextjs/dist/preset.js
- ./node_modules/@storybook/core/dist/common/index.cjs
- ./node_modules/storybook/dist/proxy.cjs
- ./node_modules/storybook/bin/index.cjs
    at Module._resolveFilename (node:internal/modules/cjs/loader:1225:15)
    at Module._resolveFilename (./node_modules/esbuild-register/dist/node.js:4794:36)
    at <anonymous> (./node_modules/next/src/server/require-hook.ts:51:34)
    at Module._load (node:internal/modules/cjs/loader:1051:27)
    at Module.require (node:internal/modules/cjs/loader:1311:19)
    at Module.mod.require (./node_modules/next/src/server/require-hook.ts:70:26)
    at require (node:internal/modules/helpers:179:18)
    at Object.<anonymous> (./node_modules/ajv-keywords/src/definitions/typeof.ts:2:1)
    at Module._compile (node:internal/modules/cjs/loader:1469:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)

I'm using the following packages:

    "@storybook/addon-essentials": "^8.3.5",
    "@storybook/addon-interactions": "^8.3.5",
    "@storybook/addon-links": "^8.3.5",
    "@storybook/addon-themes": "^8.3.5",
    "@storybook/blocks": "^8.3.5",
    "@storybook/nextjs": "^8.3.5",
    "@storybook/react": "^8.3.5",
    "@storybook/test": "^8.3.5",
    "next": "15.0.0-rc.1",
    "react": "18.3.1",
    "react-dom": "18.3.1",
    "storybook": "^8.3.5",
    "storybook-next-intl": "^1.1.6",

Not a problem, it's an RC after all.

@terrymun
Copy link
Author

terrymun commented Oct 21, 2024

@valentinpalkovic @shilman After spending some more time debugging, I have found the cause of this: if the component consumes any kind of server action that invokes cookies() or headers(), it will fail as @storybook/nextjs cannot locate the nextjs internals in v15:

'use server';

import { headers } from "next/headers";

export const dummyServerAction = async () => {
  // NOTE: This is the line that wiill causes Storybook to fail
  //       If you comment it out and replace with the line below, Storybook will work:
  //       const referrer = 'http://localhost:6006/';
  const referrer = (await headers()).get('referer');

  return {
    message: 'Server action was successful',
    referrer,
  }
}

I have successfully reproduced the issue with the following repo:

https://github.com/terrymun/nextjs15-storybook

@jciolek
Copy link

jciolek commented Nov 9, 2024

I have found a temporary workaround for this issue. All the next/* packages are aliased in the Storybook webpack configuration, so it's enough to remove them.

main.ts:

import type { StorybookConfig } from '@storybook/nextjs';

const storybookConfig: StorybookConfig = {
  // whatever other storybook config you have
  // and then:

  webpackFinal: async (config) => {
    return {
      ...config,
      resolve: {
        ...config.resolve,
        alias: {
          ...Object.fromEntries(
            Object.entries(config.resolve?.alias || {}).filter(
              // we don't want to remove the alias to `next/image`, because storybook aliases that to the mock
              ([name]) => !(name.startsWith('next') && !name.includes('image')),
            ),
          ),
        },
      },
    };
  },
};

export default storybookConfig

@tiavina-mika
Copy link

@jciolek It's working fine, thanks

@terrymun
Copy link
Author

terrymun commented Nov 11, 2024

@jciolek Your workaround worked beautifully 👏 thanks for sharing!

@valentinpalkovic
Copy link
Contributor

Heads up! We are already working on a proper fix. Shouldn't take too long to get this fixed.

@github-project-automation github-project-automation bot moved this from In Progress to Done in Core Team Projects Nov 12, 2024
@yannbf
Copy link
Member

yannbf commented Nov 13, 2024

Hey everyone! The fix is released in Storybook v8.4.3 as well as Storybook v8.5.0-alpha.4. Please give it a try and provide us feedback <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

7 participants