Search code examples
webpackwebpack-5

Webpack-5 - Webpack tries to resolve root-relative paths to images in scss (or css) and fails


I'm getting this error after upgrading to Webpack-5:

Error: Can't resolve '/path/to/image.jpg' in '/app/path/to/module/module'

The issue is with images used for css backgrounds where the files aren't stored in the repository, and are not available at build-time. (Why it's this way is a story for another time.)

The issue:

In my scss file:

background-image: url(/path/to/image.jpg);

In Webpack-4, it was left as-is, and just worked.

Webpack-5 tries processing the image and fails with the error above.

This didn't work:

Adding quotes to the path...

background-image: url("/path/to/image.jpg");

I've tried Webpacks magic comments...

/* webpackIgnore: true */
background-image: url(/path/to/image.jpg)

... but it didn't work (maybe they were getting stripped too early? - This seems to be the case as is evidenced by the dev build working in my create-react-app example)

webpack.IgnorePlugin 👎

I also tried some of the edge-case tips from here. But i think that comes in too late because Webpack already assumes that the file exists.

This worked but...

What does work, is including the absolute path to the asset:

background-image: url(https://www.example.com/path/to/image.jpg);

But that creates it's own set of problems.

Update:

I reproduced the issue in this repo:

The Webpack magic comments work for the development build, but not for the production build.

~/webpack-test$ npm run build

> webpack-test@0.1.0 build
> node scripts/build.js

Creating an optimized production build...
Failed to compile.

Module not found: Error: Can't resolve '/mypics/pom.jpg' in '/home/nodejs/webpack-test/src'

Solution

  • It turns out that the css-loader has configuration options just for this under options.url!

    Thank you Alexander Akait from the Webpack team for answering my question here.

    It has the option to pass an object that contains a filter() predicate function that should determine whether a path should be processed:

    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/i,
            loader: "css-loader",
            options: {
              url: {
                filter: (url, _resourcePath) => {
                  // Disable processing for root-relative urls under /images
                  return !/^\/images\//.test(url)
    
                  // This would disable processing for all root-relative urls:
                  // return !/^\//.test(url);
                },
              },
            },
          },
        ],
      },
    };
    

    Here is the commit I used to fix this issue in the repo mentioned in the question: https://github.com/dovidweisz/webpack-test/commit/a9e4cfc4ae0a5a8475ddd2cc114a8650846db421

    You can also disable ALL url-handling by simply passing false to options.url:

    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/i,
            loader: "css-loader",
            options: {
              url: false,
            },
          },
        ],
      },
    };