Skip to content

Unable to resolve module error and reproduction of issue #109

@jsonnull

Description

@jsonnull

I've run into a bunch of issues attempting to use @import and url() when adding CSS modules to a current project and using less-loader.

It looks like a lot of people have this error:

... and so on.

I absolutely cannot get any kind of relative file load to work. I've attempted to create a minimal reproducible test case for the issue. The repository is located here: https://github.com/jsonnull/less-modules-resolve.

npm install and npm run build to see the issue.

ERROR in ./~/css-loader?modules!./~/less-loader?sourceMap!./src/index.less
Module not found: Error: Can't resolve 'material-design-icons/MaterialIcons-Regular.ttf' in '/Users/jsonnull/less-modules-resolve/src'
 @ ./~/css-loader?modules!./~/less-loader?sourceMap!./src/index.less 6:470-528
 @ ./src/index.less
 @ ./src/index.js

See below, the file is clearly present:

├── dist
│   └── build.js
├── npm-debug.log
├── package.json
├── src
│   ├── index.js
│   ├── index.less
│   └── material-design-icons
│       ├── LICENSE
│       ├── MaterialIcons-Regular.eot
│       ├── MaterialIcons-Regular.ijmap
│       ├── MaterialIcons-Regular.svg
│       ├── MaterialIcons-Regular.ttf
│       ├── MaterialIcons-Regular.woff
│       ├── MaterialIcons-Regular.woff2
│       ├── README.md
│       ├── codepoints
│       └── material-icons.less
└── webpack.config.js

I've tried every combination for the less file import as well as the url() import I can think of...

  • file - I think this one should work?
  • ./file - I think this one should definitely work
  • ~file - I think this one should not work
  • /file - I think this one should not work

And, anyways, none of these methods work.

Assuming this is possible, how can the repository above be fixed so that all issues are resolved using the current directory structure? Otherwise, are there really combinations of relative paths that are completely impossible to use for importing?

From scrounging through issues it really does seem like nobody has a clear understanding of what this issue is or how to fix it. If we can come up with a clear answer for this issue for why it doesn't work and how to fix, hopefully others can learn from this and we can come up with good documentation for how to avoid this issue.

Activity

tamer1an

tamer1an commented on Oct 14, 2016

@tamer1an

👍 please resolve that issue
@jhnns

jhnns

jhnns commented on Oct 14, 2016

@jhnns
Member

Thx for the detailed bug report. With your description and the minimal test example I was able to spot the issue very quickly 👍

Unfortunately, that's a really tricky one, let me explain it:

  • First, webpack encounters the index.less and passes it to less-loader
  • The less-loader passes the file to less
  • Less parses the file and discovers the @import statement. Since nested imports are legal less, less is resolving the material-icons.less with the help of the less-loader
  • Now less has all the less files and compiles them down to CSS
  • During this compile step, less rewrites all urls so that the output contains the correct path. This is because the less-loader sets the relativeUrls option. This option is very useful, since it allows you to write your less files in a modular way, just reference your images and the final CSS contains valid urls. The urls look like this:
// before compilation
url('MaterialIcons-Regular.eot')
// after compilation
url('material-design-icons/MaterialIcons-Regular.eot')
// all urls are relative to index.less
  • This CSS is now passed to the css-loader with the modules option enabled. If a CSS module contains an import statement that does not start with a dot, it is considered to be a module request and webpack will search in node_modules for it.
  • If less had rewritten the url to url('./material-design-icons/MaterialIcons-Regular.eot') everything would work just fine.

It basically boils down to LESS + relativeUrls: true + CSS modules is not compatible. Either you convince less to rewrite their urls so that relative urls start with a dot, or you override the relativeUrls option in the less-loader or you get rid of less at all (I think, in combination with CSS modules less is not really necessary).

jsonnull

jsonnull commented on Nov 12, 2016

@jsonnull
Author

@jhnns Thanks for looking into this!

I'm going to close this issue, but I've left the repository in place in case anybody else comes across this issue.

m19c

m19c commented on May 10, 2017

@m19c

+1 - same problem :-/

jsonnull

jsonnull commented on May 11, 2017

@jsonnull
Author

@MrBoolean unfortunately this problem is not going away any time soon. As stated above "It basically boils down to LESS + relativeUrls: true + CSS modules is not compatible"

I migrated away from LESS because I needed CSS modules and relative imports, and CSS formats are relatively interchangeable these days.

chardlau

chardlau commented on May 25, 2017

@chardlau

@jsonnull
I found that if wrap the less file with a folder and prepend '../' when using url() can work.
files distributes like below:

[module_root]/
----index.js (Here, use import './css/index.less')
----css/
--------index.less (Here, use url('../assets/test.eot'))
----assets/
--------test.eot

It looks so ugly, but i work.

txiaocao

txiaocao commented on Sep 21, 2017

@txiaocao

Haha, I resolve it; this is hack
I create images.css,and require the css files,and use
the code

private images = require("./images");
this.images.loader
.loader{
background-image: url("./301.gif");
}
limichange

limichange commented on Jan 8, 2018

@limichange

It is fine. 🤔

.loader{
   background-image: url("\./301.gif");
}
rally25rs

rally25rs commented on Jan 15, 2018

@rally25rs

During this compile step, less rewrites all urls so that the output contains the correct path.

@jhnns is there a way to disable this? When importing a lot of 3rd party CSS files, they have url()s set to where the file will be hosted not where it is on disk. These may not be resolvable by any loader, and the files can't be edited (they come from other dependencies).

css-loader can be passed url: false to stop processing those URLs, but less-loader always changes them, making them incorrect at runtime.

rally25rs

rally25rs commented on Jan 16, 2018

@rally25rs

For those that come across this issue and find that it completely blocks them from using less-loader... for example I have styling from some 3rd party libs that have url( references to files that don't exist on disk, like chosen-bootstrap references images that ship with chosen but aren't included in chosen-bootstrap itself.

You can disable all this URL mangling with relativeUrls: false on less-loader, and url: false on css-loader.

      {
        test: /\.less/,
        use: [{
          loader: 'style-loader'
        }, {
          loader: 'css-loader',
          options: {url: false, sourceMap: true}
        }, {
          loader: 'less-loader',
          options: {relativeUrls: false, sourceMap: true}
        }]
      },

This makes all url() entries stay as they were in the original less and css source (unchanged) and webpack will no longer try to resolve them. This also means that you no longer need file-loader or url-loader to process each of those files, however you also need a build step to copy the static assets into your own deploy directory where the web server can get to them. It also means there will be hot-reloading for the less files, but not for fonts and images.

This was fine for me, as I was mostly just wanted the less file hot reloading.

garygreen

garygreen commented on Feb 20, 2018

@garygreen

@rally25rs thanks so much for that - it's worth noting that if you only need to do this for certain files you can change the rule so it only uses that loader with those custom options if needed. I'm a total noob when it comes to Webpack, so not sure if I'm doing it right but it seems to be working good for me.

Here's my current webpack config:

       {
           test: /\.less$/,
           exclude: /site.less$/,
           use: ExtractTextPlugin.extract({
               use: ['css-loader', 'less-loader'],
               fallback: 'style-loader'
           })
       },
       // Custom less compiler for frontend site less.
       // This basically just turns off resolving of url() as they should all be in the public_html already
       // so don't need to be resolved, and would cause problems if they are.
       {
           test: /site.less$/,
           use: ExtractTextPlugin.extract({
               use: [{
                   loader: 'css-loader',
                   options: {url: false, sourceMap: true}
               }, {
                   loader: 'less-loader',
                   options: {relativeUrls: false, sourceMap: true}
               }],
               fallback: 'style-loader'
           })
       },
mqliutie

mqliutie commented on May 30, 2018

@mqliutie

@garygreen Thanks for your codes

boylec

boylec commented on Oct 3, 2018

@boylec

I got this to work without needing to turn off relativeUrls by making use of 'url-loader' for fonts/images:

url-loader converts files (fonts and images in this case) into base-64 strings. This way the resulting css references for fonts and/or images is a direct base64 string representation of the image or font instead of a path (relative or otherwise).

For example:

{
    test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
    enforce: "pre", // preload the jshint loader
    use: [{
        loader: "url-loader",
        options: {
            query: { limit: 25000 }
        }
    }]
},
{
    test: /\.(png|jpg|jpeg|gif|svg)$/,
    enforce: "pre", // preload the jshint loader
    exclude: /node_modules/, // exclude any and all files in the node_modules folder
    use: [{
        loader: "url-loader",
        options: {
            query: { limit: 25000 }
        }
    }]
}

You could probably combine the loaders but I wanted them to behave slightly differently - ie exclude: /node_modules/.

matthew-dean

matthew-dean commented on Nov 21, 2018

@matthew-dean

Does the --rewrite-urls=local option resolve this issue? http://lesscss.org/usage/#less-options-rewrite-urls

Considering that @jhnns added the Less functionality, I think it addressed this issue, correct? If so, it would make sense to remove the "CSS Modules gotcha" in the readme.

Note the original issue wasn't so much even Less + relativeUrls: true (now rewriteUrls: 'all') + CSS Modules, but actually Less + relativeUrls: true + CSS modules + the Less plugin + webpack loader behavior working together to cause a problem, but the additional option should make this more flexible and compatible with Webpack + CSS modules.

matthew-dean

matthew-dean commented on Nov 21, 2018

@matthew-dean

Also, as noted in #276, no special ~ syntax should be needed to load styles from the node_modules folder. Less-loader is actually breaking Less module-loading functionality, but maybe that's by design. (I'm not a Webpack expert.)

jhnns

jhnns commented on Apr 25, 2019

@jhnns
Member

For future reference: passing {rewriteUrls: "local"} as Less option should fix the problem. Check out the Less documentation for more information.

manugb

manugb commented on Nov 1, 2019

@manugb

For remote @import urls check this out
less/less.js#3188 (comment)

kanishka-malhotra

kanishka-malhotra commented on Jun 3, 2021

@kanishka-malhotra

Following configuration helped me resolve the issue with relative URLs due to less-loader + CSS modules (mentioned here)

{
  test: /\.less$/,
  use: [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        publicPath: '/'  // NOTE: this option does the charm to add `/` in front of all relative assets (don't use `./`)
      }
    },
    {
      loader: 'css-loader',
      options: {
        importLoaders: 2,
      },
    },
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          config: path.resolve(__dirname, 'postcss.config.js'),
        },
      },
    },
    {
      loader: 'less-loader',
    },
  ],
}

Hope this helps!

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @rally25rs@m19c@matthew-dean@jhnns@tamer1an

        Issue actions

          Unable to resolve module error and reproduction of issue · Issue #109 · webpack-contrib/less-loader