Storybook: Resolving LESS imports in webpack

Created on 3 Apr 2017  Â·  5Comments  Â·  Source: storybookjs/storybook

I can't seem to figure out why Webpack isn't resolving the LESS imports inside my less files.

I have a styles npm package that has a few universally defined less variables and functions, let's just say its @brand/styles installed in ./node_modules.

My components are pretty scattered. There's some inside a project-wide shared folder at ./src/shared, entry-point specific shared folders ./src/apps/AppName/shared, and specific components ./src/*.

My current webpack.config.js inside the .storybook folder:

const path = require('path');

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

module.exports = function(config, env) {
  var config = genDefaultConfig(config, env);

  config.module.loaders.push({
    test: /\.less$/,
    loaders: [
      'style-loader',
      'css-loader?modules&importLoaders=1',
      'postcss-loader',
      'less-loader'
    ],
    include: [
      path.resolve('./src'),
      path.resolve('./node_modules/@brand/styles')
    ]
  });

  config.resolve.extensions.push('.less');

  config.resolve.alias['@brand/styles/variables.less'] = path.resolve('./node_modules/@brand/styles/variables');

  config.resolve.root = [
    path.resolve('./'),
    path.resolve('./src/shared')
  ];

  config.resolve.fallback = config.resolve.fallback.concat([
    path.resolve('./src/apps/App/shared'),
  ]);

  // console.log(JSON.stringify(config));

  return config;
};

An example of a less file:

@import '~@brand/styles/variables';

:local {
  .link {
    margin-left: @global-grid * 1.5;
    font-size: @global-grid / 2;
  }
}

I would get errors saying @global-grid is undefined. I don't see any examples for less integration so any help or insights would be really really awesome.

question / support

Most helpful comment

const path = require('path');

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

module.exports = function(config, env) {
  var config = genDefaultConfig(config, env);

  if (!config.module.rules) {
    config.module.rules = [];
  }

  config.module.rules.push({
    test: /\.less$/,
    use: [
      {
        loader: 'style-loader' // creates style nodes from JS strings
      },
      {
        loader: 'css-loader',
        options: {
          importLoaders: 2
        } // translates CSS into CommonJS
      },
      {
        loader: 'postcss-loader' // add vendor prefixes
      },
      {
        loader: 'less-loader' // compiles Less to CSS
      }
    ],
    include: [
      path.resolve('./src'),
      path.resolve('./node_modules/@brand/styles')
    ],
  });

  config.resolve.extensions.push('.less');

  if (!config.resolve.modules) {
    config.resolve.modules = [];
  }

  config.resolve.modules = config.resolve.modules.concat([
    path.resolve('./'),
    path.resolve('./src'),
    'node_modules',
    'shared',
    'src'
  ]);

  return config;
};

Yes, the less config looks something like this for webpack 2 for anyone who's interested. I only briefly tested it out with a single component story.

All 5 comments

It seems like less-loader and its module resolution doesn't play nicely with storybook 2's config at the moment. I've tried [email protected]/3.0.0/4.0.0 but all of them have trouble resolving import '~@brand/styles/filename.

Seems like it will be resolved by storybook 3 and webpack 2.

Hey @danielduan

I never use webpack aliases, because it's so confusing what's actually being required that way, but hey, it's your codebase ¯\_(ツ)_/¯. So I'm probably not the right person to answer this. But I would like to understand some things, it's not criticism!

What's the ~ for / from ? ~@brand/styles/variables, looks to me it would a valid module be without it?

Why load non-js files without a file-extension?

To me this seems super odd:

config.resolve.alias['@brand/styles/variables.less'] = path.resolve('./node_modules/@brand/styles/variables')

Storybook 3 will include webpack 2, it's resolve config has changed a bit.

I should have removed that alias, I was just trying anything to get it to work.

The ~ tells less-loader and webpack that it's a module. This was me trying to create a webpack 1 config so it could work for 2.35.3. Definitely wasn't my choice to drop the .less extension in imports.

I was able to less module resolve working with the webpack 2 from the mono repo with the example config from less-loader's readme and [email protected]. I'll mark this as closed.

Ow wow, did I understand you correctly you're using the version from the mono-repo? 😮

You are aware that could be really unstable for the next few weeks? Thanks for the feedback though! If it actually works for you, thats really imported info for me!

const path = require('path');

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

module.exports = function(config, env) {
  var config = genDefaultConfig(config, env);

  if (!config.module.rules) {
    config.module.rules = [];
  }

  config.module.rules.push({
    test: /\.less$/,
    use: [
      {
        loader: 'style-loader' // creates style nodes from JS strings
      },
      {
        loader: 'css-loader',
        options: {
          importLoaders: 2
        } // translates CSS into CommonJS
      },
      {
        loader: 'postcss-loader' // add vendor prefixes
      },
      {
        loader: 'less-loader' // compiles Less to CSS
      }
    ],
    include: [
      path.resolve('./src'),
      path.resolve('./node_modules/@brand/styles')
    ],
  });

  config.resolve.extensions.push('.less');

  if (!config.resolve.modules) {
    config.resolve.modules = [];
  }

  config.resolve.modules = config.resolve.modules.concat([
    path.resolve('./'),
    path.resolve('./src'),
    'node_modules',
    'shared',
    'src'
  ]);

  return config;
};

Yes, the less config looks something like this for webpack 2 for anyone who's interested. I only briefly tested it out with a single component story.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tomitrescak picture tomitrescak  Â·  3Comments

arunoda picture arunoda  Â·  3Comments

shilman picture shilman  Â·  3Comments

sakulstra picture sakulstra  Â·  3Comments

miljan-aleksic picture miljan-aleksic  Â·  3Comments