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

I can not import with absolute path in Storybook #3916

Closed
mrsekut opened this issue Jul 24, 2018 · 31 comments
Closed

I can not import with absolute path in Storybook #3916

mrsekut opened this issue Jul 24, 2018 · 31 comments

Comments

@mrsekut
Copy link

mrsekut commented Jul 24, 2018

Version

  • @storybook/addon-actions: 3.4.8
  • @storybook/addon-links: 3.4.8
  • @storybook/addon-storyshots: 3.4.8
  • @storybook/addons: 3.4.8
  • @storybook/react: 3.4.8
  • React: 16.4.2
  • TypeScript: 2.9.2

Behavior

An error will be displayed in storybook when creating the following components.

# src/components/organisms/ParentComponent/index.tsx
import * as React from 'react';
import ChildrenComponent from 'src/components/molecules/ChildrenComponent/index';

const ParentComponent: React.SFC<{}> = ({ ...props }) => (
  <ChildrenComponent />
);

Error
Module not found: Error: Can't resolve 'src/components/molecules/ChildrenComponent/index' in '/AppRoot/src/components/organisms/ParentComponent'

This seems to be caused by loading with an absolute path, so if you do the following it works fine.
import ChildrenComponent from '../../molecules/ChildrenComponent/index';

However, I would like to avoid this method as much as possible. Is there no way to start storybook without errors other than specifying by relative path?

The application of the absolute path is based on the following description of tsconfig.json.

"compilerOptions": {
  "outDir": "build/dist",
  "rootDir": "src",
  "baseUrl": "."
}

Also, this time we are importing a stories file written in tsx extension in compiled src directory rather than compiled build/dist directory on storybook this time.

This is set in ./storybook/config, but setting it tobuild/dist will produce similar results.

Since this project uses atomic design, it has roughly the following directory structure.

src
├── components
│    ├── molecules
│    │   ├── ChildrenComponent
│    │   │   ├── index.tsx
│    │   │   └── index.stories.tsx
│    ├── organisms
│    │   ├── ParentComponent
│    │   │   ├── index.tsx
│    │   │   └── index.stories.tsx

Related issues

There seemed to be something like the relevant issue.
However, it did not reach a solution.
#333 , #3438

Digression

As an aside, I believe there are two ways to solve this problem.

The first thing I would like to ask here is to "Import absolute path component with storybook", the The second is to compile to a js file which imports the imported tsx file with an absolute path as a relative path. After that, apply the imported js file with the relative path to storybook.

Regarding the latter, I think it is not appropriate to listen to this problem here, but if you know it, I would like to ask about that method as well.

Thanks for your time.

@igor-dv
Copy link
Member

igor-dv commented Jul 24, 2018

I don't know how does it work for you in your regular app (like what is your setup ?), but if you will put your cwd (assuming -> cwd/src/components/.... ) to the resolve.modules in the extended webpack.config, it should probably solve your problem (I've checked it with an Angular app though, but it does not really matter)

@mrsekut
Copy link
Author

mrsekut commented Jul 25, 2018

My .storybook/webpack.config.js file is described as follows.
Is there a problem here?

const genDefaultConfig = require('@storybook/react/dist/server/config/defaults/webpack.config.js');

module.exports = (baseConfig, env) => {
	const config = genDefaultConfig(baseConfig, env);

	config.module.rules.push({
		test: /\.(ts|tsx)?$/,
		exclude: /node_modules/,
		include: [/stories/, /src/],
		loader: 'ts-loader'
	});
	config.resolve.extensions.push('.ts', '.tsx');

	return config;
};

@igor-dv
Copy link
Member

igor-dv commented Jul 25, 2018

Try adding something like this:

const path = require('path');

// blah blah code

module.exports = (baseConfig, env) => {

  // blah blah code

  config.resolve.modules = [
    ...(config.resolve.modules || []),
    path.resolve('./'),
  ];
}

@mrsekut
Copy link
Author

mrsekut commented Jul 25, 2018

It worked properly!!
I cannot thank you enough!!!!!!!

@igor-dv
Copy link
Member

igor-dv commented Jul 25, 2018

u-r-welcome

@igor-dv igor-dv closed this as completed Jul 25, 2018
@lukeAnderson2015
Copy link

lukeAnderson2015 commented Aug 1, 2018

@igor-dv I am having a similar issue, and have tried your suggestion (above), as well as the NormalModuleReplacementPlugin which modifies the resource.request path. Neither have worked

Do you have any other suggestions?

@igor-dv
Copy link
Member

igor-dv commented Aug 1, 2018

Can you please share your code examples / webpack.config.js ?

@lukeAnderson2015
Copy link

lukeAnderson2015 commented Aug 1, 2018

.storybook/webpack.config.js

const path = require('path');`
// const webpack = require('webpack');
const genDefaultConfig = require('@storybook/react/dist/server/config/defaults/webpack.config.js');

module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
config.module = {
rules: [
{
test: /.tsx$/,
loaders: ["ts-loader"],
include: path.resolve(__dirname, '../app/xv/')
},
{
test: /.scss$/,
loaders: [
'style-loader',
'css-loader',
'sass-loader?includePaths[]=' + encodeURIComponent(path.resolve(__dirname, '../app/'))
]
},
{
test: /.css$/,
loader: 'style-loader!css-loader'
},
{
test: /.less$/,
loader: 'style-loader!css-loader!less-loader'
},
{
test: /.js|.ts$/,
exclude: [path.join(__dirname, 'app/components'), /node_modules/],
loader: 'ng-annotate-loader'
},
{
test: /.js$/,
exclude: [path.join(__dirname, 'app/components'), /node_modules/],
loader: 'babel-loader?presets[]=es2015&presets[]=stage-1&presets[]=react&cacheDirectory'
}
]
};

config.resolve.modules = [
    ...(config.resolve.modules || []),
    path.resolve('./'),
];

return config;
// ,
// plugins: [
//     new webpack.NormalModuleReplacementPlugin(/xv/, function(resource) {
//         resource.request = resource.request.includes('xv/') ? '../../app/' + resource.request : resource.request;
//     })
// ]

}`

// code

`import * as React from 'react';

import { autobind } from 'xv/util/decorators';

import '../styles/ActionIcon.scss';`

// error

`ERROR in ./app/xv/ui/components/ActionIcon.tsx

Module not found: Error: Can't resolve 'xv/util/decorators' in '/Users/lukasanderson/workspace/NeXgen-UI/app/xv/ui/components'

@ ./app/xv/ui/components/ActionIcon.tsx 31:0-46
@ ./.storybook/stories/actionIcons.js
@ ./.storybook/config.js
@ multi ./node_modules/@storybook/react/dist/server/config/polyfills.js ./node_modules/@storybook/react/dist/server/config/globals.js (webpack)-hot-middleware/client.js?reload=true ./.storybook/config.js`

with /xv/ being mapped to the base of the project (root/app/xv/*) in the usual webpack dev (non storybook) build

sorry for the formatting

I've tried different variations of the regex replacement with NormalModuleReplacementPlugin, some found in similar threads/issues about storybook not handling absolute paths

example:

plugins: [ new webpack.NormalModuleReplacementPlugin(/xv/, function(resource) { resource.request = resource.request.replace(/xv/, '../../app/'); }) ]

gives me this error:

`ERROR in ./.storybook/stories/actionIcons.js

Module not found: Error: Can't resolve '../../app//ui/components/Tooltip' in '/Users/lukasanderson/workspace/NeXgen-UI/.storybook/stories'

@ ./.storybook/stories/actionIcons.js 5:0-47
@ ./.storybook/config.js
@ multi ./node_modules/@storybook/react/dist/server/config/polyfills.js ./node_modules/@storybook/react/dist/server/config/globals.js (webpack)-hot-middleware/client.js?reload=true ./.storybook/config.js
`

and this change (adding /xv/ to the replacement string)

plugins: [ new webpack.NormalModuleReplacementPlugin(/xv/, function(resource) { resource.request = resource.request.replace(/xv/, '../../app/xv/'); }) ]

gives

`ERROR in ./.storybook/stories/actionIcons.js

Module not found: Error: Can't resolve '../../app/xv//ui/components/Tooltip' in '/Users/lukasanderson/workspace/NeXgen-UI/.storybook/stories'

@ ./.storybook/stories/actionIcons.js 5:0-47
`

when I have the correct path replacement for absolute paths, not only are the relative paths messed up, but the path is 'correct' and an error persists:

ERROR in ./.storybook/stories/actionIcons.js Module not found: Error: Can't resolve '../../app/xv/ui/components/Tooltip' in '/Users/lukasanderson/workspace/NeXgen-UI/.storybook/stories'

@igor-dv
Copy link
Member

igor-dv commented Aug 1, 2018

What is your working directory (cwd)?

@lukeAnderson2015
Copy link

lukeAnderson2015 commented Aug 1, 2018

root/

  • .storybook
  • app
    -- xv
    ---ui
    ----components
    ---utils

@lukeAnderson2015
Copy link

I start storybook from NeXgen-UI (aka project root)

@igor-dv
Copy link
Member

igor-dv commented Aug 1, 2018

So having this import { autobind } from 'xv/util/decorators'; you should probably add path.resolve('./app') to the resolve.modules

@lukeAnderson2015
Copy link

lukeAnderson2015 commented Aug 1, 2018

alright, so I now have this

`
config.resolve = {

    modules: [

        ...(config.resolve.modules || []),

        path.resolve('./app'),

        path.resolve('./')

    ]
};

return config;

`

and am getting the same:

`ERROR in ./app/xv/ui/components/ActionIcon.tsx

Module not found: Error: Can't resolve 'xv/util/decorators' in '/Users/lukasanderson/workspace/NeXgen-UI/app/xv/ui/components'
`

@igor-dv
Copy link
Member

igor-dv commented Aug 2, 2018

Looks like you need to add config.resolve.extensions.push('.ts', '.tsx'); as well

@lukeAnderson2015
Copy link

@igor-dv I gave that a go as well, same error. Thanks for the help on this

@igor-dv
Copy link
Member

igor-dv commented Aug 2, 2018

🤔 I think I need to see the reproduction, then. Do you have a public repo?

@glocore
Copy link
Contributor

glocore commented Mar 26, 2019

For me, it worked by adding __dirname to path.resolve in my webpack config, like this: (I'm working on a create-react-app + TypeScript setup):

config.resolve.modules = [
  ...(config.resolve.modules || []),
  path.resolve(__dirname, "../"),
  path.resolve(__dirname, "../src")
];

My file structure, adjust yours accordingly:

/root
    /.storybook
        webpack.config.js
    /src

@gerrytan
Copy link

The stupid thing I failed to realise is I forgot to add a leading ../ to my resolve.modules config.

Here's what works for me:

// .storybook/webpack.config.js
module.exports = {
  ...,
  resolve: {
    modules: [path.resolve(__dirname, "../src"), "node_modules"],
  }
}

This is because my storybook webpack config is located 1 directory deeper in the default .storybook dir.

@kexinlu1121
Copy link

In case anyone is looking at this for storybook 5,

const path = require('path');

module.exports = ({ config }) => {
  config.resolve.modules.push(path.resolve(__dirname, "../src"));
  return config;
};

@titchimoto
Copy link

You beautiful person @kexinlu1121. It worked perfectly, thank you.

@kumarashwin
Copy link

@glocore's solution was the hint I needed for it to work. Thanks!

@wzulfikar
Copy link

I had similar issue where my absolute import works in start-storybook but not when I build. I'll just put it here for reference if someone wants some reference.

I'm using @src for absolute import and made it work by adding this line:

# /root/.storybook/webpack.config.js

const path = require("path");

module.exports = ({ config }) => {
  // ...

  // Add absolute path.resolve so storybook can handle absolute import (eg. @src/resources/...)
  config.resolve.alias = {
    ...config.resolve.alias,
    "@src": path.resolve(__dirname, "../src"),
  };
  
  return config;
};

For context, my project directory looks like this:

/root
  .storybook/
    webpack.config.js
  src/
    components/

Hope it helps :)

@klikstermkd
Copy link

@wzulfikar Thank your for your solution!

@chidioguejiofor
Copy link

I got this issue after using CLI and I was able to resolve it by modifying my .storybook/main.js to:

const path = require('path');

module.exports = {
  ...other settings....,

  webpackFinal: async (config) => {
    config.resolve.modules = [
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "../src"),
    ];

    return config;
  },

}

@castroCrea
Copy link

castroCrea commented Oct 8, 2020

Hello
I'm using React/TS
I got the same issue my .storybook/main.js:

const path = require('path');

module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app",
    "@storybook/addon-knobs",
  ],
  webpackFinal: async (config) => {

    config.resolve.alias = {
      ...config.resolve.alias,
      'fs': path.resolve(__dirname, 'fsMock.js'),
      'child_process': path.resolve(__dirname, 'fsMock.js'),
      'net': path.resolve(__dirname, 'fsMock.js'),
      'tls': path.resolve(__dirname, 'fsMock.js'),
      // "src/types": path.resolve(__dirname, "../src/types"),
      // "src/components": path.resolve(__dirname, "../src/components"),
    };

    config.resolve.modules = [
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "../src"),
    ];

    // config.resolve.extensions.push('.ts', '.tsx');

    return config;
  },
}

my structure

.storybook
src
├── components
|     index.ts
│   ├── ChildrenComponent
│    │  ├── index.tsx
│    │  └── index.stories.tsx
│   ├── ParentComponent
│    │    ├── index.tsx
│    │    └── index.stories.tsx
├── stories

A ParentComponent component

import React from "react";
import { ChildrenComponent } from "src/components";
import { ItemType } from "src/types";

export default ({ item }: { item: ItemType }) => {
  return (
    <p className="hello">
      <ChildrenComponent type={item.type} />
      <span className="ellipsis">{item.title}</span>
    </p>
  );
};

The problem come from src/components because is I do src/components/ChildrenComponent it works.

I don't get it I tried everything here and #333 #3291 and many others

A screen shot of the error
image

Can anyone help ?

@wyllie
Copy link

wyllie commented Dec 18, 2020

Sorry, this is a fairly late reply. I have the same set up as you an I got his working by changing this:

config.resolve.modules = [
  ...(config.resolve.modules || []),
  path.resolve(__dirname, "../src"),
];

To this:

      config.resolve.modules = [ 
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "src"),
    ];       

Hopefully that helps (someone)!

@imanish003
Copy link

imanish003 commented Feb 23, 2021

For storybook 6.0, You may do this in main.js file

const path = require("path");

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app",
  ],
  // ************* Add this **********
  webpackFinal: async (config) => {
    config.resolve.modules = [
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "../src"),
    ];

    return config;
  },
};

@roger-ngx
Copy link

@wzulfikar thanks a ton, bro

@dalmeria
Copy link

I had similar issue where my absolute import works in start-storybook but not when I build. I'll just put it here for reference if someone wants some reference.

I'm using @src for absolute import and made it work by adding this line:

# /root/.storybook/webpack.config.js

const path = require("path");

module.exports = ({ config }) => {
  // ...

  // Add absolute path.resolve so storybook can handle absolute import (eg. @src/resources/...)
  config.resolve.alias = {
    ...config.resolve.alias,
    "@src": path.resolve(__dirname, "../src"),
  };
  
  return config;
};

For context, my project directory looks like this:

/root
  .storybook/
    webpack.config.js
  src/
    components/

Hope it helps :)

// webpack.config.js

const path = require('path')

module.exports = ({ config }) => {
  // ...

  // Add absolute path.resolve so storybook can handle absolute import (eg. @src/resources/...)
  config.resolve.alias = {
    ...config.resolve.alias,
    '@': path.resolve(__dirname, '../src'),
  }

  return config
}

@ChuckJonas
Copy link

Note:

If you are using typescript with baseUrl, the path you resolve should match that path.

So if you have "baseUrl": ".",, you'd want this instead

webpackFinal: async (config) => {
    config.resolve.modules = [
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "../"),
    ];
    return config;
  },

@sepsol
Copy link

sepsol commented Dec 28, 2021

For storybook 6.0, You may do this in main.js file

const path = require("path");

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app",
  ],
  // ************* Add this **********
  webpackFinal: async (config) => {
    config.resolve.modules = [
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "../src"),
    ];

    return config;
  },
};

I'm using storybook@6.4.9 with webpack5 and I'm getting errors when I try this:

ModuleNotFoundError: Module not found: Error: Can't resolve 'path' in '/path/to/project/node_modules/@storybook/store/dist/esm'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
        - install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "path": false }

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

No branches or pull requests