Mark Priem
Mark Priem

Reputation: 397

Webpack file-loader publicPath

I have a react project in which I'm using webpack 3.10.0 with file loader 1.1.6 to move some images and json files into my distribution folder.

Webpack emits the files as expected, but react receives the wrong urls for my json and images assets

My markup looks like:

<img src="../images/helloworld_a49183cf48e4a0f12aa2124fe2ed9d3a.png" 
alt="Hello World!!">

but should be:

<img src="/assets/images/helloworld_a49183cf48e4a0f12aa2124fe2ed9d3a.png" 
alt="Hello World!!">

My folder structure looks like below: C:. ├───dist │ └───assets │ ├───css │ ├───data │ ├───images │ └───js ├───src │ ├───css │ ├───data │ ├───images │ └───js │ ├───actions │ ├───components │ ├───containers │ └───reducers └───tests

I thought file-loader publicPath should take care of this, but it seems I'm either misunderstanding or something is wrong with my configuration. Can someone be so kind to help me out?

webpack.config.js

var path = require('path');
const ExtractCSS = require("extract-text-webpack-plugin");

module.exports = {
  entry: [
    './src/js/index.js'
  ],
  output: {
    path: path.resolve(__dirname, 'dist/assets/js'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['env','react']
          }
        }
      },
      {
        test: /\.scss$/,
        loader: ExtractCSS.extract('css-loader!sass-loader')
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name (file) {
                /*if (env === 'development') {
                  return '[path][name].[ext]'
              }*/
                return '[name]_[hash].[ext]'
              },
              publicPath: '/assets/images/',
              outputPath: '../images/'
            }  
          }
        ]
      },
      {
        test: /\.json$/,

        use: [
          {
            loader: 'file-loader',
            options: {
              name (file) {
                /*if (env === 'development') {
                  return '[path][name].[ext]'
              }*/
                return '[name].[ext]'
              },
              publicPath: '/assets/data/',
              outputPath: '../data/'
            }  
          }
        ]
      }
    ]
  },
  plugins: [
    new ExtractCSS('../css/app.css', {
        allChunks: true
    }) 
  ],
  resolve: {
    extensions: ['.js', '.jsx']
  },
  //devtool: 'eval-source-map',
  devServer: {
    historyApiFallback: true,
    contentBase: './dist/'
  }
};

Upvotes: 5

Views: 17089

Answers (3)

Mark Priem
Mark Priem

Reputation: 397

This morning after my machine had rebooted, the issue changed?!!? (caching issue??!)... Instead of ignoring publicPath it now concatenated publicPath with outputPath. Same issue as explained here: https://github.com/webpack-contrib/file-loader/issues/228

Reverting back to 0.10.1 resolves my issue.

Thanks for everyone who tried to help!

Upvotes: 1

ChrisR
ChrisR

Reputation: 4008

You can also configure your output object to be a level above and then specify only the name of your files:

  output: {
    path: path.resolve(__dirname, 'dist/assets'),
    filename: 'js/bundle.js'
  },

And for example for the json:

{
    test: /\.json$/,
    use: [
        {
            loader: 'file-loader',
            options: {
                name: 'data/[name].[ext]',
            }
      }
    ]
}

Upvotes: 1

mu_sa
mu_sa

Reputation: 2735

So, instead of

{
    test: /\.(png|jpg|gif)$/,
    use: [
      {
        loader: 'file-loader',
        options: {
          name (file) {
            /*if (env === 'development') {
              return '[path][name].[ext]'
          }*/
            return '[name]_[hash].[ext]'
          },
          publicPath: '/assets/images/',
          outputPath: '../images/'
        }  
      }
    ]
  },

You could try something like

{
    test: /\.(png|jpg|gif)$/,
    use: [
      {
        loader: 'file-loader',
        options: {
          name (file) {
            /*if (env === 'development') {
              return '[path][name].[ext]'
          }*/
            return '[name]_[hash].[ext]'
          },
          publicPath: function(url) {
              return url.replace(../, '/assets/')
          },
        }  
      }
    ]
  },

Upvotes: 3

Related Questions