Storybook: Storybook is not able to resolve path with Next js absolute import

Created on 22 Jul 2020  路  23Comments  路  Source: storybookjs/storybook

Describe the bug
Storybook is not able to resolve path with Next js absolute import

To Reproduce
Steps to reproduce the behavior:
yarn add storybook
Added .storybook folder
Add jsconfig for absolute import

Expected behavior
It should build correctly.

const path = require('path');
const resolve = (dir) => path.resolve(__dirname, dir);

module.exports = ({ config }) => {
  config.resolve.alias = {
    '@utils/*': resolve('../src/utils/*'),
   ....
  };

  return config;
};

Error


ERROR in ./src/components/Base/Button/Button.jsx
Module not found: Error: Can't resolve '@utils/boxShadowGenerator' in '/Users/rahulshrivastava/projects/unacademy-web-learning/src/components/Base/Button'
 @ ./src/components/Base/Button/Button.jsx 9:0-59 107:35-53 122:9-27
 @ ./src/stories/button.stories.js
 @ ./src/stories sync \.stories\.js$
 @ ./.storybook/config.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/config.js (webpack)-hot-middleware/client.js?reload=true&quiet=true

Code snippets
I am using jsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2016",
    "jsx": "react",
    "baseUrl": "./src/",
    "paths": {
      "@utils/*": ["utils/*"],
    ....
    }
  },
  "exclude": ["node_modules", "dist"]
}

System:

 npx -p @storybook/cli@next sb info

Environment Info:
(node:1828) UnhandledPromiseRejectionWarning: TypeError: e.filter is not a function
    at /Users/rahulshrivastava/.npm/_npx/1031/lib/node_modules/@storybook/cli/node_modules/envinfo/dist/envinfo.js:1:73205
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async Promise.all (index 6)
(node:1828) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:1828) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
P1 babel / webpack compatibility with other tools documentation has workaround nextjs question / support

Most helpful comment

Its because thats not an absolute import from root, your path is using an alias. The following code allows you to import from src using "src/components/button/Button":

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

But it does not tell webpack anything about the "@/Components" syntax. You would need to pass an alias configuration like this:

config.resolve.alias = {
      ...config.resolve.alias,
      "@/Components": path.resolve(__dirname, "../src/components")
    };

All 23 comments

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

I have exactly the same problem! I tried adding a tsconfig.json and with a custom webpack but didn't work.

+1 - Same issue here. Any idea on how to process Next.js paths in jsconfig.json? I found this on TypeScript (haven't tested it) but need one on Javascript instead: https://github.com/storybookjs/storybook/issues/9610

+1 Same problem here. NextJS resolves but SB don't.

jsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./src"
  }
}

@kalanda That's correct, Next.js resolve but SB don't. I tried a lot of webpack solutions and multiple tsconfig.json options but anyone was successful. I decided to remove SB for my project for now. Sad.

I havent gotten everything working with Next yet but this resolved the absolute import issues (in .storybook/webpack.config.js):

const path = require('path');

module.exports = ({config}) => {
  config.resolve.modules = [
    path.resolve(__dirname, ".."),
    "node_modules",
  ]

  return config
}

For using ./src, you can use path.resolve(__dirname, "..", "src"),

With SB 6.x you don't have a webpack configuration, instead you use a main.js file with specific import structure (see Storybook React Configure Preview). Please, could you provide the same code in this format?

I havent gotten everything working with Next yet but this resolved the absolute import issues (in .storybook/webpack.config.js):

const path = require('path');

module.exports = ({config}) => {
  config.resolve.modules = [
    path.resolve(__dirname, ".."),
    "node_modules",
  ]

  return config
}

For using ./src, you can use path.resolve(__dirname, "..", "src"),

You can still add a webpack.config.js to your .storybook directory. But with main.js, you define it as webpackFinal:

const path = require('path');

module.exports = {
  stories: ["../stories/*.stories.@(js|jsx)"],
  addons: [
    "@storybook/addon-actions",
    "@storybook/addon-knobs",
    "@storybook/addon-links",
  ],
  presets: ["@storybook/preset-scss"],
  webpackFinal: async (config, { configType }) => {
    config.resolve.modules = [
      path.resolve(__dirname, ".."),
      "node_modules",
    ]

    return config;
  }
};

Hello! I've just tried this fix in a project with Nextjs v9.5.3 and Storybook v6.0.21 but its not working.

On the path /sb-test/stories/Button.stories.js on the the 2nd and 3rd lines you can switch between absolute and relative paths.
The absolute path works but if i use the relative path it doesn't work.

//import { ButtonComponent } from "../src/components/button/Button";
import { ButtonComponent } from "@/Components/button/Button";

This is the error:
image

ERROR in ./stories/Button.stories.js
Module not found: Error: Can't resolve '@/Components/button/Button' in '/mnt/c/Users/reape/sb-test/stories'
@ ./stories/Button.stories.js 85:0-61 88:13-28 97:42-57
@ ./stories sync ^.(?:(?:^|\/|(?:(?:(?!(?:^|\/).).)?)\/)(?!.)(?=.)[^/]?.stories.(js|jsx|ts|tsx))$
@ ./.storybook/generated-stories-entry.js
@ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/storybook-init-framework-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/common/config.js-generated-other-entry.js ./node_modules/@storybook/addon-docs/dist/frameworks/react/config.js-generated-other-entry.js ./node_modules/@storybook/addon-links/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addDecorator.js-generated-other-entry.js ./node_modules/@storybook/addon-actions/dist/preset/addArgs.js-generated-other-entry.js ./node_modules/@storybook/addon-backgrounds/dist/preset/defaultParameters.js-generated-other-entry.js ./.storybook/preview.js-generated-config-entry.js ./.storybook/generated-stories-entry.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined

Its because thats not an absolute import from root, your path is using an alias. The following code allows you to import from src using "src/components/button/Button":

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

But it does not tell webpack anything about the "@/Components" syntax. You would need to pass an alias configuration like this:

config.resolve.alias = {
      ...config.resolve.alias,
      "@/Components": path.resolve(__dirname, "../src/components")
    };

Great! It worked perfectly, thanks a lot man. I wrote a commit implementing your fix: Absolute path with Storybook problem solved

I love you man, I spent like about 40 hours trying to solve but I never could. Thanks <3

Its because thats not an absolute import from root, your path is using an alias. The following code allows you to import from src using "src/components/button/Button":

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

But it does not tell webpack anything about the "@/Components" syntax. You would need to pass an alias configuration like this:

config.resolve.alias = {
      ...config.resolve.alias,
      "@/Components": path.resolve(__dirname, "../src/components")
    };

haha no problem, glad I could help 馃嵒

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

Is this the preferred way to solve this, should perhaps be added to the docs if it is?

Hey @eric-burel do you mind taking a look at this one?

Basically the underlying issue, is that you need to reuse the same Webpack config in both Next and Storybook, and make sure your Webpack config is robust enough to be reused, eg using __dirname

For example I use this in Vulcan:

const withMagicImports = (config = {}) => {
  if (!config.resolve) config.resolve = {};
  config.resolve.alias = {
    ...config.resolve.alias,
    "~": path.join(__dirname, "../../../", "src"),
  };
  config.resolve.modules = [
    ...(config.resolve.modules || []),
    path.join(__dirname, "../../../", "packages"),
  ];
  return config;
};

I use that both in next.config.js and main.js to extend the Webpack config. It is robust to path changes because I use __dirname.

Maybe I can add a section in https://storybook.js.org/docs/react/configure/webpack for this advanced usage with a code sample if that's a pretty common issue?

I've built a repro: https://github.com/lbke/next-sb-default-absolute-imports

I'll try to see if we can make it work out of the box in Storybook by using the same pattern as Next.

In the meantime the official solution is to get the Storybook config right in order to have the same behavior as Next, as demonstrated in the comment above.

@shilman Everything is happening in this file in Next packages/next/build/webpack-config.ts as far as I can tell. It will parse tsconfig and jsconfig to explicitely compute webpack alias based on the paths. I am asking Next people to get confirmation. Could it be worthy to add this in Storybook also? I'll try to demo that but it'll take a bit of time.

Next webpack "magic" provides an examplary developer experience, while being rather safe and robust to change since it is based on standard features of jsconfig.json and tsconfig.json files. Webpack is more obfuscated within the framework, as it should be in the best of world.
I wouldn't mind have most of the same features in Storybook.

We might want to check this experimental plugin from Next: https://github.com/vercel/next.js/tree/canary/packages/next-plugin-storybook, it makes use of Next webpack config
It would make sense in my opinion to go even further and abstract it a bit to support some feature for all Storybook project, not just Next, the alias thing is a good example of something you may want in any TS project.

@eric-burel it would be fantastic if the plugin was updated and allowed Storybook 6.x to be integrated more smoothly. So far i've tested it in a dummy repo and once you run yarn storybook it yields the following:

next-plugin-error

Based on a preliminary search it seems that the last change done to the plugin was pre 6.x release date, around 5/6 months ago.

I'm going to raise an issue asking if the plugin is going to be updated to support Storybook 6.0 as it would help out not only Storybook users and NextJs users as well.

See https://github.com/vercel/next.js/pull/18364
When fixed the preset works perfect, I'll PR a TypeScript version in Next to make it more robust

Even better: https://github.com/vercel/next.js/pull/18367
If someone is good at TypeScript, giving some help to fix packages/next-plugin-storybook/tsconfig.json to finish the PR would be awesome. This would make the plugin more reliable.

Was this page helpful?
0 / 5 - 0 ratings