Storybook: Resolve alias in webpack config

Created on 2 Apr 2018  ยท  8Comments  ยท  Source: storybookjs/storybook

Tools version

  • webpack: 4.2.0,
  • storybook/cli: 3.3.15,
  • storybook/react: 3.3.15,

Problem

Even using alias at webpack.config.js inside the .storybook folder, and in my root project folder, it seems storybook doesn't apply the aliases, resulting in a conflict of paths. If I want to run storybook, I need to update my static files paths to ../../../, and if I want to run a webserver, I need to update my static files paths to ../.

My code

.storybook/webpack.config.js

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

module.exports = {
  resolve: {
    alias: {
      atoms: path.resolve(__dirname, 'src/client/atoms/'),
      client: path.resolve(__dirname, 'src/client/'),
      fonts: path.resolve(__dirname, 'src/fonts/'),
      helpers: path.resolve(__dirname, 'src/helpers/'),
      images: path.resolve(__dirname, 'src/images/'),
      stories: path.resolve(__dirname, 'src/stories/'),
      styles: path.resolve(__dirname, 'src/styles/'),
      tests: path.resolve(__dirname, 'src/tests/'),
    },
    extensions: ['.js', '.jsx', '.css', '.png', '.jpg', '.gif', '.jpeg'],
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          require.resolve('style-loader'),
          {
            loader: require.resolve('css-loader'),
            options: {
              importLoaders: 1,
              modules: 1,
              localIdentName: '[path]-[name]-[local]',
            },
          },
          {
            loader: require.resolve('postcss-loader'),
            options: {
              ident: 'postcss',
              plugins: () => [
                require('postcss-import'),
                require('postcss-cssnext')({
                  features: {
                    customProperties: false,
                  },
                }),
              ],
            },
          },
        ],
      },
      {
        test: /\.(woff|jpg|png|gif|jpeg)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 65000,
          },
        },
      },
    ],
  },
};

fonts.css

@font-face {
  font-family: "Roboto";
  src: url("../../../fonts/Roboto-Regular.woff");
  font-weight: normal;
}

button.js

const getImage = () => {
    const imageTypes = {
      positive: {
        src: require('../../../images/icons/up.png'), //eslint-disable-line
        alt: 'Positivo',
      },
      negative: {
        src: require('../../../images/icons/down.png'), //eslint-disable-line
        alt: 'Negativo3',
      },
      neutral: {
        src: 'neutral.jpg',
        alt: 'Neutro',
      },
    }

    return imageTypes[type]
  }

Extra explication

Command "start": "webpack-dev-server --mode development --open"
All paths ../../../ will only works if changed to ../.

Command "storybook": "start-storybook -p 9001",
All paths ../../../ will works.

Who to contact

@allangrds

babel / webpack question / support

Most helpful comment

I solved my problem, following the code:

.storybook/webpack.config.js

const path = require('path');
const paths = require('./paths.js')
const includePath = path.resolve(__dirname, '..');

module.exports = {
  resolve: {
    alias: {
      atoms: path.resolve(__dirname, '../src/client/atoms/'),
      client: path.resolve(__dirname, '../src/client/'),
      fonts: path.resolve(__dirname, '../src/fonts/'),
      helpers: path.resolve(__dirname, '../src/helpers/'),
      images: path.resolve(__dirname, '../src/images/'),
      molecules: path.resolve(__dirname, '../src/client/molecules/'),
      stories: path.resolve(__dirname, '../src/stories/'),
      styles: path.resolve(__dirname, '../src/styles/'),
      tests: path.resolve(__dirname, '../src/tests/'),
    },
    extensions: ['.js', '.jsx', '.css', '.png', '.jpg', '.gif', '.jpeg'],
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          require.resolve('style-loader'),
          {
            loader: require.resolve('css-loader'),
            options: {
              importLoaders: 1,
              modules: 1,
              localIdentName: '[path]-[name]-[local]',
            },
          },
          {
            loader: require.resolve('postcss-loader'),
            options: {
              ident: 'postcss',
              plugins: () => [
                require('postcss-import'),
                require('postcss-cssnext')({
                  features: {
                    customProperties: false,
                  },
                }),
              ],
            },
          },
        ],
        include: paths.appSrc,
      },
      {
        test: /\.(jpg|png|gif|jpeg)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 65000,
          },
        },
      },
      {
        test: /\.woff$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[path][name].[ext]',
            outputPath: 'fonts',
            publicPath: '../fonts',
          },
        },
      },
    ],
  },
};

path.js

const path = require('path')
const fs = require('fs')
const url = require('url')

const appDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(appDirectory, relativePath)

const envPublicUrl = process.env.PUBLIC_URL

function ensureSlash (path, needsSlash) {
  const hasSlash = path.endsWith('/')

  if (hasSlash && !needsSlash) {
    return path.substr(path, path.length - 1)
  }

  if (!hasSlash && needsSlash) {
    return `${path}/`
  }

  return path
}

const getPublicUrl = appPackageJson =>
  envPublicUrl || require(appPackageJson).homepage

function getServedPath (appPackageJson) {
  const publicUrl = getPublicUrl(appPackageJson)

  const servedUrl =
    envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/')
  return ensureSlash(servedUrl, true)
}

module.exports = {
  appPublic: resolveApp('public'),
  appHtml: resolveApp('public/index.html'),
  appBuild: resolveApp('public/'),
  appIndexJs: resolveApp('src/index.js'),
  appPackageJson: resolveApp('package.json'),
  appSrc: resolveApp('src'),
  yarnLockFile: resolveApp('yarn.lock'),
  appNodeModules: resolveApp('node_modules'),
  publicUrl: getPublicUrl(resolveApp('package.json')),
  servedPath: getServedPath(resolveApp('package.json')),
}

I put a file with all my paths, and use in storybook webpack config file.

All 8 comments

__dirname in node is the directory of current module, in this case it's your .storybook directory. So it probably should be atoms: path.resolve(__dirname, '../src/client/atoms/') etc

Hi @Hypnosphi! Thanks for answering me.
So, even after changing to code posted by you, I still have the problem with the path for my css file and js - importing a image.

I need to use the same path when run command to storybook or webserver.

But the whole point of adding resolve.alias is to avoid relative paths. You should be able to require('images/icons/down.png') etc

Anyway, it's weird that you have to change the path, assuming that your files stay in same location. Can you share some minimal reproduction part of your project on GitHub so that I could debug it myself?

myProject/src
โ”œโ”€โ”€ client
โ”‚ย ย  โ”œโ”€โ”€ App.css
โ”‚ย ย  โ”œโ”€โ”€ App.js
โ”‚ย ย  โ”œโ”€โ”€ atoms
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ Button
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ index.css
โ”‚ย ย  โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ index.js
โ”œโ”€โ”€ fonts
โ”‚ย ย  โ”œโ”€โ”€ Roboto-Regular.woff
โ”œโ”€โ”€ helpers
โ”‚ย ย  โ”œโ”€โ”€ http.js
โ”‚ย ย  โ””โ”€โ”€ request.js
โ”œโ”€โ”€ images
โ”‚ย ย  โ””โ”€โ”€ icons
โ”‚ย ย      โ”œโ”€โ”€ down.png
โ”‚ย ย      โ””โ”€โ”€ up.png
โ”œโ”€โ”€ index.html
โ”œโ”€โ”€ index.js
โ”œโ”€โ”€ stories
โ”‚ย ย  โ”œโ”€โ”€ Button
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ index.js
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ style.css
โ””โ”€โ”€ styles
    โ”œโ”€โ”€ generic
    โ”‚ย ย  โ”œโ”€โ”€ normalize.css
    โ”‚ย ย  โ””โ”€โ”€ others.css
    โ”œโ”€โ”€ index.css
    โ””โ”€โ”€ settings
        โ”œโ”€โ”€ colors.css
        โ””โ”€โ”€ fonts.css

myProject/.storybook
โ”œโ”€โ”€ config.js
โ””โ”€โ”€ webpack.config.js

Sorry, I meant in a repo. I can't debug just by folder structure

I solved my problem, following the code:

.storybook/webpack.config.js

const path = require('path');
const paths = require('./paths.js')
const includePath = path.resolve(__dirname, '..');

module.exports = {
  resolve: {
    alias: {
      atoms: path.resolve(__dirname, '../src/client/atoms/'),
      client: path.resolve(__dirname, '../src/client/'),
      fonts: path.resolve(__dirname, '../src/fonts/'),
      helpers: path.resolve(__dirname, '../src/helpers/'),
      images: path.resolve(__dirname, '../src/images/'),
      molecules: path.resolve(__dirname, '../src/client/molecules/'),
      stories: path.resolve(__dirname, '../src/stories/'),
      styles: path.resolve(__dirname, '../src/styles/'),
      tests: path.resolve(__dirname, '../src/tests/'),
    },
    extensions: ['.js', '.jsx', '.css', '.png', '.jpg', '.gif', '.jpeg'],
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          require.resolve('style-loader'),
          {
            loader: require.resolve('css-loader'),
            options: {
              importLoaders: 1,
              modules: 1,
              localIdentName: '[path]-[name]-[local]',
            },
          },
          {
            loader: require.resolve('postcss-loader'),
            options: {
              ident: 'postcss',
              plugins: () => [
                require('postcss-import'),
                require('postcss-cssnext')({
                  features: {
                    customProperties: false,
                  },
                }),
              ],
            },
          },
        ],
        include: paths.appSrc,
      },
      {
        test: /\.(jpg|png|gif|jpeg)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 65000,
          },
        },
      },
      {
        test: /\.woff$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[path][name].[ext]',
            outputPath: 'fonts',
            publicPath: '../fonts',
          },
        },
      },
    ],
  },
};

path.js

const path = require('path')
const fs = require('fs')
const url = require('url')

const appDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(appDirectory, relativePath)

const envPublicUrl = process.env.PUBLIC_URL

function ensureSlash (path, needsSlash) {
  const hasSlash = path.endsWith('/')

  if (hasSlash && !needsSlash) {
    return path.substr(path, path.length - 1)
  }

  if (!hasSlash && needsSlash) {
    return `${path}/`
  }

  return path
}

const getPublicUrl = appPackageJson =>
  envPublicUrl || require(appPackageJson).homepage

function getServedPath (appPackageJson) {
  const publicUrl = getPublicUrl(appPackageJson)

  const servedUrl =
    envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/')
  return ensureSlash(servedUrl, true)
}

module.exports = {
  appPublic: resolveApp('public'),
  appHtml: resolveApp('public/index.html'),
  appBuild: resolveApp('public/'),
  appIndexJs: resolveApp('src/index.js'),
  appPackageJson: resolveApp('package.json'),
  appSrc: resolveApp('src'),
  yarnLockFile: resolveApp('yarn.lock'),
  appNodeModules: resolveApp('node_modules'),
  publicUrl: getPublicUrl(resolveApp('package.json')),
  servedPath: getServedPath(resolveApp('package.json')),
}

I put a file with all my paths, and use in storybook webpack config file.

@allangrds You are awesome!!! Thank you! Searched all day for this. :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexanbj picture alexanbj  ยท  3Comments

wahengchang picture wahengchang  ยท  3Comments

MrOrz picture MrOrz  ยท  3Comments

dnlsandiego picture dnlsandiego  ยท  3Comments

miljan-aleksic picture miljan-aleksic  ยท  3Comments