Webpack url-loader or file-loader not working react app

Eric Steen picture Eric Steen · Oct 3, 2019 · Viewed 8.8k times · Source

Images are not loading in the browser using Webpack 4 with either of url-loader, or file-loader. Small images are not in data url(or if they are the browser isn't showing them) and file network requests are not being made with file loader.

Nginx is serving the images properly at https://{server}/images/image_name.png, but not https://{server} and no network calls for images are being made in web inspector network panel.

Best guess so far is Webpack url-loader or file-loader must not be generating the right URL. Cannot find the host when searching app.bundle.js for the url. I've tried for days every combination of publicPath, outputPath, etc.. from all the other stackoverflow posts, nothing works.

Is there any way to view the url's that webpack generates besides searching the js? Is the webpack config not proper? Troubleshooting advice?

Here is how I handle images in code:

import nav_logo from "Images/white_nav_logo.svg";

<img src={nav_logo} />

Here is my webpack.common.js:

module.exports = {
  mode: mode,
  entry: {
    app: ["./src/js/app.js"]
  },
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: '[name].bundle.js',
    publicPath: '/',
    chunkFilename: '[name].bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.(sc|c|)ss$/,
        issuer: {
          exclude: /\.less$/,
        },
        use: [
          {
            loader:  'style-loader',
            options: {
            },
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              localIdentName: '[name]-[local]-[hash:base64:5]',
            },
          },
        ],
      },

      {
        test: /\.less$/,
        use: [
          {
            loader:  'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            },
          },
        ],
      },
      {
        test: /\.(jsx?)/,
        exclude: ["/node_modules", "/src/js/elm"],
        use: [
          { loader: "babel-loader?cacheDirectory=true",
          }
        ]
      },
      {
        test: /\.scss$/,
        issuer: /\.less$/,
        use: {
          loader: './src/js/sassVarsToLess.js'
        }
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: 'images/[name].[ext]',
            }
          },
          {
            loader: "image-webpack-loader",
            options: {
              disable: true,
              mozjpeg: {
               progressive: true,
               quality: 65
              },
              // optipng.enabled: false will disable optipng
              optipng: {
               enabled: true,
              },
              pngquant: {
               quality: '65-90',
               speed: 4
              },
              gifsicle: {
               interlaced: false,
              },
              // the webp option will enable WEBP
              webp: {
               quality: 75
              }
            }
          },
        ],
      },
      {
        test: /\.(ttf|otf|eot|woff2?)$/,
        loader: "file-loader",
        options: {
          name: 'fonts/[name].[ext]',
        }
      }
    ],
    noParse: [/\.elm$/]
  },
  node: {
    fs: 'empty'
  },
  plugins: [
    new Dotenv(),
    new CopyWebpackPlugin([{
      from: "./src/assets/css",
      to: "css"
    },
  ]),
  ]
};

and webpack.prod.js

module.exports = merge(common, {
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.(sc|c|)ss$/,
        issuer: {
          exclude: /\.less$/,
        },
        use: [
          {
            loader:  MiniCssExtractPlugin.loader,
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              localIdentName: '[name]-[local]-[hash:base64:5]',
            },
          },
        ],
      },
      {
        test: /\.less$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            }
          },
        ],
      },
      {
        test: /\.(jsx?)/,
        exclude: ["/node_modules", "/src/js/elm"],
        use: [
          { loader: "babel-loader?cacheDirectory=true",
          }
        ]
      },
      {
        test: /\.scss$/,
        issuer: /\.less$/,
        use: {
          loader: './src/js/sassVarsToLess.js' // Change path if necessary
        }
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: 'images/[name]-[hash:8].[ext]'
            }
          },
          {
            loader: "image-webpack-loader",
            options: {
              disable: false,
              mozjpeg: {
               progressive: true,
               quality: 65
              },
              // optipng.enabled: false will disable optipng
              optipng: {
               enabled: true,
              },
              pngquant: {
               quality: '65-90',
               speed: 4
              },
              gifsicle: {
               interlaced: false,
              },
              // the webp option will enable WEBP
              webp: {
               quality: 75
              }
            }
          },
        ],
      },
      {
        test: /\.(ttf|otf|eot|woff2?)$/,
        loader: "file-loader",
        options: {
          name: 'fonts/[name].[ext]',
        }
      }
    ],
    noParse: [/\.elm$/]
  },
  optimization: {
    minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin({})]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/assets/prod.index.html'
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
  ],
})

and here is nginx default.conf

server {
    listen       80;
    server_name  <domain_name>;
    root /usr/share/nginx/html;
    access_log  /var/log/nginx/host.access.log  main;

    index index.html;

    location / {
      try_files $uri $uri/ =404;
    }

    location /images/ {
      alias /usr/share/nginx/html/images/;
      try_files $uri $uri/ =404;
      error_log /var/log/nginx/error.log debug;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

Answer

Ankit Tiwari picture Ankit Tiwari · Oct 28, 2020

For loading images using url-loader

If you notice inside config/webpack.config.js There is a module object which has rules object inside it. For the rules or list of rules provided there is limit key limit key is very important

Significance of limit value -if the size of image to be loaded is greater than the limit value provided then by default file-loader is used. e.g if I have below webpack.config.js configuration

{
  test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
  loader: require.resolve('url-loader'),
  options: {
             limit: 10000,
             name: 'static/media/[name].[hash:8].[ext]',
           },
},

inside my moudules -> rules object

Above the limit value is 10000 bytes so webpack will load only those images using url-loader whose size is less than 10000 bytes if size of image is found equal to or greater than 10000 then file-loader is used by default until fallback loader is not specified.

So suppose if you are dynamically adding a image something like this inside your code.

import largeimage from '../static/images/largeimage.jpg' or whatever path and the size of largeimage is less than the limit value the image will not get loaded.

SOLUTION

For the webpack to load the image using url-loader your largeimage size should be less than limit value.

So either increase limit or decrease size of image.

Reference https://webpack.js.org/loaders/url-loader/#limit