webpacksass-loaderresolve-url-loader

Webpack 4 with sass-loader & resolve-url-loader - Image paths not being found


Minimally reproducible setup here: https://github.com/jamesopti/webpack_playground/tree/resolve_url_loader_issue

Im trying to use resolve-url-loader to add a hashname to my scss url() image paths, but I'm having a heck of a time getting it to work with webpack 4. I have a bunch of images in /static/img/** which are referenced in my SCSS like:

span.arrow {
  background: url(/static/img/audiences.png);
}

Which is ending up in my css as exactly the same thing (resolve-url-loader isnt finding them)

When I run the following configuration through webpack, I see that resolve loader is finding the right url() and its path, but debug mode is saying NOT FOUND.

resolve-url-loader: /static/img/audiences.png
  /Users/usr1/webpack_playground/src
  /Users/usr1/webpack_playground/static/img
  NOT FOUND

Is there some output config thats not correct? I've tried various combinations of the settings to no avail:

  loader: 'resolve-url-loader',
  options: {
    debug: true,
    root: path.join(__dirname, './static/img'),
    includeRoot: true,
    absolute: true,
  },

My end goal is for file-loader to transform them to the /dist hashed version:

span.arrow {
  background: url(/static/img/audiences-dhsye47djs82kdhe6.png);
}

// Webpack rules config

rules: [
      {
        test: /\.(png|jpg|gif)$/,
        include: [
          path.resolve(__dirname, './static/img'),
        ],
        use: {
          loader: 'file-loader',
          options: {
            name: '[name]-[hash].[ext]',
          },
        },
      },
      {
        test: /\.svg$/,
        use: {
          loader: 'svg-inline-loader',
          options: {
            name: '[name]-[hash].[ext]',
          },
        },
      },
      { test: /\/src\/js\/(?:.*)\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' } ] },
      {
        test: [/\.scss$/, /\.sass$/],
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
            },
          },
          {
            loader: 'resolve-url-loader',
            options: {
              debug: true,
              root: './static/img',
              includeRoot: true,
            },
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'compressed',
              sourceMap: true,
              includePaths: [
                './src'
              ],
            },
          },
        ],
      },
]

Solution

  • It turns out all I needed was file-loader to do what I wanted.

    When an image (matching my specified file extensions) is encountered by any of the css/sass/style loaders, its processed through file-loader, which both copies it to the output directory specified with the naming format specified and returns the name for the sass loader to use as the file name.

    rules: [
      {
        test: /\.(png|jpg|gif|svg)$/,
        exclude: [
          path.resolve(__dirname, './node_modules'),
        ],
        use: {
          loader: 'file-loader',
          options: {
            name: '[path][name]-[hash].[ext]',
            outputPath: '../',
            publicPath: '/dist',
          },
        },
      },
      {
        test: /\.svg$/,
        include: [
          path.resolve(__dirname, './node_modules'),
        ],
        use: {
          loader: 'svg-inline-loader',
          options: {
            name: '[name]-[hash].[ext]',
          },
        },
      },
      { test: /\/src\/js\/(?:.*)\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' } ] },
      {
        test: [/\.scss$/, /\.sass$/],
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
              root: path.resolve(__dirname),
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                autoprefixer({
                  'browsers': ['last 2 versions', 'ie >= 10'],
                }),
              ],
              sourceMap: true,
            },
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'compressed',
              sourceMap: true,
              includePaths: [
                './src/scss',
              ],
            },
          },
        ],
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
            options: {
              root: path.resolve(__dirname),
            },
          },
        ],
      },
      {
        test: [
          /\/bundles\/(?:.*)\.js$/,
        ],
        use: {
          loader: 'babel-loader',
        },
      },
    ];