Webpack 4: mini-css-extract-plugin + file-loader not loading assets
Asked Answered
D

6

14

I'm trying to move assets (images and fonts) used in one of my .scssfiles, but it seems that they get ignored:

This is my .scss file:

@font-face {
    font-family: 'myfont';
    src: url('../../assets/fonts/myfont.ttf') format('truetype');
    font-weight: 600;
    font-style: normal;
}

body {
    color: red;
    font-family: 'myfont';
    background: url('../../assets/images/bg.jpg');
}

And this is my webpack.config.js:

const path = require('path');
const { CheckerPlugin } = require('awesome-typescript-loader');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    target: 'node',
    entry: path.resolve(__dirname, 'server.tsx'),
    output: {
        filename: 'server_bundle.js',
        path: path.resolve(__dirname, 'build'),
        publicPath: '/build'
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.jsx']
    },
    module: {
        rules: [{
                test: /\.(tsx|ts)?$/,
                loader: 'awesome-typescript-loader',
                options: {
                    jsx: 'react'
                }
            },
            {
                test: /\.(scss|sass|css)$/,                
                use: [
                    MiniCssExtractPlugin.loader,
                    { loader: 'css-loader', options: { url: false, sourceMap: true } },
                    { loader: 'sass-loader', options: { sourceMap: true } },                    
                ]
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/,
                loader: 'file-loader',
                options: { outputPath: 'public/images' }
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                loader: 'file-loader',
                options: { outputPath: 'public/fonts' }
            }
        ]
    },
    plugins: [
        new CheckerPlugin(),
        new MiniCssExtractPlugin({
            filename: 'public/styles_bundle.css',
            chunkFilename: "public/styles/[id].css"
        })
    ]
}

I'm getting this .css file in my browser as the output (Note the name of the image):

body {
  color: red;
  background: url("../../assets/images/myimage.jpg"); 
}

And in my public directory I get this:

public/
    styles_bundle.css

There are two problems here:

  1. Fonts are not compiled (No public/fonts/etc...)
  2. Images are not compiled

I've been trying everything, but I don't know what may be happening here... Any Ideas?

Decorous answered 24/12, 2018 at 22:25 Comment(6)
re 2: in your build, images names are hashed by default to enable cache (webpack.js.org/guides/caching). To change it add name: 'images/[name][hash:8].[ext]' property to your options in image file rules (remove [hash:8] if you don't want to use hash).Nesmith
What if you leave out the outputPath option?Espresso
No luck either :(Decorous
@Decorous Any solution ?Laird
Would love to see an answer to this.Shel
It's incredible how few accepted answers there are with webpack loaders. Nobody seems to know what is going on.Mcwherter
B
8

I have just fixed a similar issue. If you change the url option to true, you might see failed image URL references.

{ loader: 'css-loader', options: { url: false, sourceMap: true } },

Or you can manual check whether the path reference is correct.

url('../../assets/images/bg.jpg')

I think the images folder doesn't get created because all the image resource links are incorrect.

For the problem I was fixing, the references were all wrong and I couldn't fix them so I just used this webpack copy plugin to copy files to the right dist folder location.

Bookstall answered 5/3, 2019 at 20:32 Comment(0)
I
4

you need url-loader

           {
               test: /\.(jpg|png|gif|woff|eot|ttf|svg)/,
                use: {
                    loader: 'url-loader', // this need file-loader
                    options: {
                        limit: 50000

                    }
                }
           }
Interposition answered 6/3, 2019 at 19:1 Comment(0)
T
2

try the below configuration

{
    test: /\.s[ac]ss$/i,
    use: [
      {
        loader: MiniCssExtractPlugin.loader, 
        options: {
            publicPath: ''
        }
    },
    {
        loader: "css-loader", 
        options: { sourceMap: true}
    },{
      loader: "sass-loader", 
      options: { sourceMap: true }
    }
    ]
  },
  {
    test: /\.(png|jpg|jpeg|gif)$/i,
    loader: 'file-loader',
    options: { outputPath: 'assets/images', publicPath: '../images', useRelativePaths: true }
  },
  {
    test: /\.(woff|woff2|eot|ttf|otf)$/i,
    loader: 'file-loader',
    options: { outputPath: 'assets/fonts', publicPath: '../fonts', useRelativePaths: true }
  }

enter image description here

After this my scss file started accepting the relative URL and the compiled files also mapped accordingly using relative path.

Trier answered 15/11, 2020 at 18:35 Comment(0)
L
1

The mini-css-extract-plugin has a 'publicPath' option (see here). It basically tells the generated css where the external resources like fonts, images, etc are to be found. In my case, setting it to '../' and configuring all the file loaders to their proper directories, this worked perfectly. Basically looks like:

rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '/public/path/to/',  // <-- This is what was helping. 
            },
          },
          'css-loader',
        ],
      },
    ],
Landrum answered 16/4, 2021 at 19:17 Comment(0)
M
0

I had this issue too. I was using the following versions:

package.json

"mini-css-extract-plugin": "^0.10.1",
"webpack": "^5.3.1",

For me everything was compiling just fine until I added the following into a scss file:

.xmas {
    background-image: url("./img/Xmas2020/SurveyBanner.png");
    height: 150px;
}

The backgound-image url was the problem. When I changed it to an absolute path it worked:

.xmas {
    background-image: url("/img/Xmas2020/SurveyBanner.png");
    height: 150px;
}

webpack.config.js

This is just to show how I was putting images into the output directory. I guess there are different ways to do this, but I was using CopyWebpackPlugin.

plugins: [
   new CopyWebpackPlugin({
        patterns: [
            { from: './src/static/img', to: './img', force: true },
        ]
    }),
  ]

This link helped me https://github.com/webpack-contrib/mini-css-extract-plugin/issues/286#issuecomment-455917803

Mcwherter answered 15/12, 2020 at 2:19 Comment(0)
M
0

Had the exact problem with webpack 5. The answer is in Asset Modules

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
   assetModuleFilename: 'images/[hash][ext][query]' //set the pattern for your filename here
  },
  module: {
    rules: [
      {
        test: /\.png/,
        type: 'asset/resource' //replaces file-loader, url-loader etc
      }
    ]
  },
};

Macri answered 6/4, 2022 at 7:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.