webpack/css-loader

css-loader conflicts with file-loader

Closed this issue · 2 comments

Bug report

Actual Behavior

I have this basic webpack configuration set up, with a single css file that should be processed for testing:

{
    mode: "development",
    devtool: "source-map",
    entry: "./test.css",
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/[name].[contenthash].css',
            chunkFilename: 'css/[name].[id].css',
        })
    ],
    module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif|ico)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[hash].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }
        ]
    }
}

My test.css looks like this:

.test {
    background-image: url("./public/assets/images/logo.png");
}

If I run this, it seems to me that the requested image is processed by both rules in the configuration, which results in a mangled image file somehow. The output of the build is a folder, with the following files:

+ css
    - main.[hash].css
    - main.[hash].css.map
- [hash].png
- logo.[otherhash].png
- main.js
- main.js.map

If I try to open the [hash].png file, it is a corrupted image file, the logo.[otherhash].png file is my relating image file, and the main.[hash].css is pointing to the corrupted image file.

Expected Behavior

I encountered this error while migrating to the new webpack, and to newer versions of css-loader. In the old version, images that were required in my css (and scss) files where only handled by the first rule in the config, by the file-loader. What I would expect, is to either create one hashed image (that is not corrupted), and reference that inside the output css file, or at least reference the uncorrupted image file in my end css.

How Do We Reproduce?

Just use the above mentioned webpack configuration, with any simple css file, and any png image for reference.

What I also tried:

  • I tried to set the url configuration option in css-loader to false, in which case css-loader is not processing the image anymore, but in this case my first rule is ignoring it as well.
  • I tried to remove the file-loader (the first rule in my config), which solved the issue, however that is not viable for me, because my real code also imports jpg files from .js code, where the css-loader is not running.
neeh commented

Just ran into the same issue. It turns out file-loader is deprecated. If you still need file-loader, simply downgrade css-loader to ^5.2.7, otherwise here's what I did:

I replaced file-loader:

{
  test: /\.(jpg|png|svg|bin|glb|mp3|mp4|webm|eot|woff|ttf|otf)$/,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: 'assets/[name].[hash:8].[ext]',
        esModule: false
      }
    }
  ]
}

With asset/resource:

{
  test: /\.(jpg|png|svg|bin|glb|mp3|mp4|webm|eot|woff|ttf|otf)$/,
  type: 'asset/resource'
}

And moved the path pattern in the output parameter:

output: {
  path: path.resolve(__dirname, 'dist'),
  filename: 'bundle.js',
  assetModuleFilename: 'assets/[hash][ext][query]'
}

Please avoid using file-loader and migrate to asset modules, here more infromation https://webpack.js.org/guides/asset-modules/, another solutions is set esModule: false or set type: 'javascript/auto', feel free to feedback