Search code examples
javascriptwebpackurlloader

404s on some images from Webpack url-loader


There are a lot of questions on this, and a lot of answers, read below to see what I've tried, and how they didn't work. I assume my problem is coming from a fundamental misunderstanding of how url-loader works.

I have images included like this in my .less files. I am using two different formats as an example of what I've tried.

app.less

#logo {
  background-image: url("~/img/LoginMarketingImage.png");
}
#logotwo{
  background-image: url("../public/img/LoginMarketingImage2.png");
}

webpack.config.js

module.exports = {
    context: path.resolve(__dirname, '../../'),
    entry: {
        app: './public/js/app.js'
    },
    output: {
        path: path.resolve(__dirname, '../build'),
        filename: '[name].js',
        publicPath: '/'
    },

I have also tried

webpack.config.js

module.exports = {
    context: path.resolve(__dirname, '../../'),
    entry: {
        app: './public/js/app.js'
    },
    output: {
        path: path.resolve(__dirname, '../build'),
        filename: '[name].js',
        publicPath: ''
    },

As well as below, based on: webpack css-loader not finding images within url() reference in an external stylesheet

webpack.config.js

module.exports = {
    context: path.resolve(__dirname, '../../'),
    entry: {
        app: './public/js/app.js'
    },
    output: {
        path: path.resolve(__dirname, '../build'),
        filename: '[name].js',
        publicPath: 'https://localhost:9081/'
    },

My module config looks like

webpack.config.js

   module: {
        rules: [
        {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader',
            options: {
                limit: 2000000,
                name: utils.assetsPath('img/[name].[ext]')
            }
        },
     ]
   }

I have experimented with a limit of 1 and a higher limit, to see if inline vs non-inlined works.

My folder structure is as follows

  build/
  less/
     app.less
  public/
     img/
        LoginMarketingImage.png
        LoginMarketingImage2.png

  config/
     webpack/
        webpack.config.js

My Results

If I set the limit to 1, and force all images to be output directly, the only time they are output is if they use the url("../") syntax. url("~/") throw no webpack errors, but the images don't get output to the build folder. In this case, the images using url("../") syntax throw no errors in the browser either. However, this is not ideal, as I want to take advantage of url-loader's ability to return a DataURL. In this scenario, images using url("~/") syntax give the error GET https://localhost:9081/img/logo.png 404 (Not Found), regardless of publicPath setting.

If I set the limit to 20000000, obviously no images are put in the build folder by file-loader. However, all images return a 404 in the browser, regardless of publicPath setting.

I feel like I'm misunderstanding how to use url-loader. What kind of configuration do I need, and how should I be requiring my files inside less, to take advantage of url-loader's ability to return DataURLs?

EDIT: Based on this issue, I have ensured that css sourcemaps are disabled.


Solution

  • I can't pinpoint the problem here, but it seems like the publicPath config is the problem. I threw together a sample gist with the minimium you need to get the url-loader working properly.

    Some things to note:

    • Make sure the test option is correct
    • You didn't mentioned which version of webpack you're using, but I assume it's > 2. If it's == 2 then you should upgrade because the newer versions fixed a lot of bugs and the config API is almost 100% compatible
    • Do not use the tilde import path, it's a shortcut to project-root-dir/node_modules (at least in webpack 1.x)
    • I assume you're using webpack-dev-server. If not, then you should not need to set the publicPath and such
    • Do not change url-loader's name option unless you got everything working without it. Changing it's path can confuse webpack