Css-loader: :local + url(File) - unexpected behaviour

Created on 20 Oct 2015  ยท  19Comments  ยท  Source: webpack-contrib/css-loader

this works well

:local(.selectLocale) {
  background: url(SelectLocale72x72.png) no-repeat 90% #eee;
}

This (without brackets)

:local .selectLocale {
  background: url(SelectLocale72x72.png) no-repeat 90% #eee;
}

throws an error

ERROR in ./~/css-loader!./~/cssnext-loader!./src/components/SelectLocale.css
Module not found: Error: Cannot resolve module 'SelectLocale72x72.png'

That's a bug, right? Or I missed something? What form should I use? Very confusing and unexpected. I've read a mention about that, but it explained nothing to me :(

Most helpful comment

Please reopen the issue. It still exists more than one year, css-loader cannot resolve url without modules: true.

All 19 comments

When you use :local (or css-modules local by default, as I have been using) - the pathing is different to the standard loader syntax.

See here:
https://github.com/webpack/css-loader/blob/master/README.md#local-scope

url(...) URLs in block scoped (:local .abc) rules behave like requests in modules:

./file.png instead of file.png
module/file.png instead of ~module/file.png

@haustraliaer I read this and I didn't get it. How should I rewrite url to get my example working without brackets? Because url(./SelectLocale72x72.png) doesn't work either.

Not sure - would have to know where the file was on your system - and where the css file was that's calling it. This, for example - works for me:

// _index.scss:

.Login__logo {
  background-image: url(./dial-logo.png);
}

screen shot 2015-10-21 at 6 09 57 pm

So if your image isn't directly in the same folder as your css declaration then url(./SelectLocale72x72.png) will not work. But also, if your image is not in a folder that is defined by webpack or browserify or whatever as a "module" folder - then url(images/SelectLocale72x72.png) will also not work.

In my case the image is in the same folder as .css. Your example doesn't contains local. My original issue was about unexpected behaviour when using :local .class syntax, without :local or with :local(.class) the issue doesn't appear. Maybe I didn't express myself clear enough in the original post. So the problem is when using both: url + :local .class syntax

Ah sorry - I did understand that, but as I mentioned I'm using css-modules - which uses local by default (so I would assume the behaviour to be the same). I'm only answering this because I had the same problem, but fixed it after going through the readme again.

Edit: It does seem like what you're experiencing is a bug, however - I didn't read properly that the :local(...) syntax did work. I've also found some odd things when trying to define :global (again, using module mode). So I ended up avoiding it.

@haustraliaer nevertheless thanks for the attempt to help)

Did you try prepending the URL to the image with "./"? I don't know why it would make a difference with or without the parenthesis, maybe with the parenthesis, only the class is defined as local but without the parenthesis the entire rule is considered local so the URL needs to follow the local path rules?

:local(.selectLocale) {
  background: url(SelectLocale72x72.png) no-repeat 90% #eee;
}

should be replaceable with:

:local .selectLocale {
  background: url(./SelectLocale72x72.png) no-repeat 90% #eee;
}

@sokra @joezimjs as I mentioned above, url(./SelectLocale72x72.png) doesn't work either (throws the same error).

@alexbyk Missed that one sorry

As mentioned in https://github.com/webpack/css-loader/issues/282#issuecomment-225313262

Prepending ../dir to the URL seems to get around this problem (even though it is really redundant).

@alexbyk how did you end up solving this?

I have a component, that has JS, SCSS and Images that are used by SCSS in components directory.

โ”œโ”€โ”€ NavT
โ”‚ย ย  โ”œโ”€โ”€ some-asset.png
โ”‚ย ย  โ”œโ”€โ”€ index.js
โ”‚ย ย  โ”œโ”€โ”€ NavT.js
โ”‚ย ย  โ””โ”€โ”€ NavT.scss

[email protected], [email protected]

    {
      test: /^((?!\.global).)*\.s?css$/i,
      loaders: [
        'style-loader',
        'css-loader?modules&importLoaders=3&localIdentName=[name]__[local]___[hash:base64:5]&sourceMap&camelCase',
        'postcss-loader',
        'resolve-url-loader?keepQuery',
        'sass-loader?sourceMap'
      ]
    },
    {
      test: /\.(png|jpg|jpeg|gif|svg)$/,
      loader: (production || testing)
        ? 'url-loader?limit=50000!image-webpack-loader'
        : 'url-loader?limit=50000'
    },

So local (via modules query) enabled by default.

Class that uses

.myClass {
  background-image: url('./some-asset.png');
}

will throw

ERROR in ./~/css-loader?modules&importLoaders=3&localIdentName=[name]__[local]___[hash:base64:5]&sourceMap&camelCase!./~/postcss-loader!./~/resolve-url-loader?keepQuery!./~/sass-loader?sourceMap!./src/React-Components/NavT/NavT.scss
Module not found: Error: Cannot resolve module 'some-asset.png' in /full/abs/path/to/src/React-Components/NavT

I tried the

:local(.myClass) {
  background-ulr: url('some-asset.png'); // also ./
}

:local .myClass {
  background-ulr: url('some-asset.png'); // also ./
}

but still the same error (and if this worked, then it still would be o_O, because everything is local by default).

For classes in other places that use url(), but are inside :global {} wrapper everything works. Namely - webfonts - urls get resolved and webpack-dev-server serves them as expected.

I can test it within the same NavT.scss

This throws

span {
  background-image: url('./some-asset.png');
}

This passes

global: span {
  background-image: url('./some-asset.png');
}

the issue is caused by cssnano that I use as one of PostCSS plugins. the trick is to force set normalizeUrl: false which apparently is set to true by default. :man_facepalming:

config.postcss = function () {
  let postPluginConf = [];
  postPluginConf.push(
    require('autoprefixer')({
      browsers: ['> 0.0001%'],
      cascade: true,
      remove: true
    })
  );
  postPluginConf.push(
    require('css-mqpacker')()
  );
  if (production || testing) {
    postPluginConf.push(
      require('cssnano')({
        discardComments: {
          removeAll: true
        },
        zindex: false,
        normalizeUrl: false
      })
      // ["zindex", "normalizeUrl", "discardUnused", "mergeIdents", "reduceIdents"]
    );
  }
  return postPluginConf;
};

@alexbyk You still have this issue ? ๐Ÿ˜›

Closing due to inactivity, please test with latest css-loader and feel free to reopen if still regressions

login
โ”œโ”€โ”€ Login.jsx
โ”œโ”€โ”€ login-bg.jpg
โ””โ”€โ”€ style.less
This show error: Module not found: Error: Can't resolve 'login-bg.jpg'

.root {
    background: url(./login-bg.jpg);
}

But, this works well

.root {
    background: url(../login/login-bg.jpg);
}

why?

@zkboys are you using _resolve-url-loader_ (you should)?

@kroko i got the same problem as @zkboys , use resolve-url-loader doesn't help

Please reopen the issue. It still exists more than one year, css-loader cannot resolve url without modules: true.

Was this page helpful?
0 / 5 - 0 ratings