Css-loader: CSS modules break build if used with `~`

Created on 4 Aug 2017  路  15Comments  路  Source: webpack-contrib/css-loader

Module not found: Error: Can't resolve '~'

What is the current behavior?

Using a tilde ~ inside a css file causes Can't resolve '~' if css-modules feature is activated:

{
  loader: 'css-loader',
  options: {
    modules: true,
  }
},

If the current behavior is a bug, please provide the steps to reproduce.

The bug can be reproduced this way: (https://github.com/jantimon/css-loader-bug)

git clone https://github.com/jantimon/css-loader-bug.git
cd css-loader-bug
npm install
npm run without-modules 
npm run with-modules

Working webpack.config.js
Broken webpack.config.js
CSS File

What is the expected behavior?

Compilation should work even if modules are set to true.

Motivation

I wrote a loader which adds ~!! to a css file and it does not know if the user is using css-modules: https://github.com/jantimon/iconfont-webpack-plugin/blob/master/lib/postcss-plugin.js#L135-L137

4 (important) Patch 3 (broken) Bug

Most helpful comment

Is this considered an inconsistency? I wish I could fix this.

All 15 comments

@jantimon why don't use url('file-loader!flags-of-the-world/src/DK.svg')? It is works.

@evilebottnawi this won't work if modules are set to false.

I am looking for a syntax which can be used with different css-loader configs for my plugin

For now I am working around this issue by forcing the user to tell me wether he is using cssModules or not:

https://github.com/jantimon/iconfont-webpack-plugin/blob/master/example/module/webpack.config.js#L30

Is this considered an inconsistency? I wish I could fix this.

Is this considered an inconsistency?

Yes, it definitely is. I believe this also may be the cause of some confusion in issues like #12.

Seems bug PR welcome!

Just information: @import "~normalize.css/normalize.css"; also don't works, seems all syntax don't works

I had the same issue, it seems kinda counterintuitive:

:global { * { background: url('~assets/my-asset.svg'); } } // works
:local { * { background: url('~assets/my-asset.svg'); } } // does not work
:local { * { background: url('assets/my-asset.svg'); } } // no tilde here but works

That is odd behaviour.

Because of this resolving the actual URL is context-sensitive making global variables ala bootstrap-sass (e.g. $styleguilde-asset-url / $bootstrap-font-url) awkward to use.

I find the reason: https://github.com/webpack-contrib/css-loader/blob/master/lib/processCss.js#L163-L174
If open the css module, the mode is 'local', url will reserve the ~,such as:

:local { * { background: url('~assets/my-asset.svg'); } }
// urlToRequest
:local { * { background: url(require('~assets/my-asset.svg')); } }

else the mode is 'global', url will recognize the ~ ,https://github.com/webpack/loader-utils/blob/67499ff3d13c13ef455ec0fede90b714fc16d787/lib/urlToRequest.js#L50-L52,and remove the ~,require file as a module.such as:

:global { * { background: url('~assets/my-asset.svg'); } }
// urlToRequest
:global { * { background: url(require('assets/my-asset.svg')); } }

Using vue-loader which allows modules to be turned on or off per