0

I am trying to make my webpack.config work with images in subfolders. And I am having troubles with it. I spent the last day and a half scouring the internet and reading various solutions to no avail.

My src files are:

/src/images/data/

/src/containers

My problem is: I have a Route that is: http://localhost:7771/games/O that load from /src/containers On that page, I am trying to load /src/images/data/NotFound.png

If I call the image using: <img src="../images/data/NotFound.png"/> then the image shows without any problem.

But, if I change the path to <img src={require("../images/data/NotFound.png")}/> then the image does not show. When I inspect the image using Chrome developer Tools I see that the element appears as: <img src="images/data/NotFound.png"> If I hover the src link I see: http://localhost:7771/games/images/data/NotFound.png But if I try to open that link, the image does not load.

hover link

If I navigate to http://localhost:7771/images/data/NotFound.png instead, then the image loads.

I tried using an alias for resolve and changed the image to <img src={require("~/data/NotFound.png")}> but the result is the same, the image does not load.

That's why I think my webpack.config is messed up and I would like some help to figure out what is wrong with it so that my image can show.

var webpack = require('webpack');
var path = require('path');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var CircularDependencyPlugin = require('circular-dependency-plugin');
var BUILD_DIR =  path.resolve(__dirname,'htmlhot');
var APP_DIR = path.resolve(__dirname, 'src');
// Load environment variables from .env file. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
require('dotenv').config({silent: true});

var config = {
  context: path.join(__dirname, "src"),
    devtool: 'source-map',
  entry: [
      //'webpack/hot/dev-server',
    // reload controls falling back to page refresh if hot reload fails (  rare ).
    // change to false to debug hot reloading, so you can see the errors before it refreshes the page.
     'webpack-hot-middleware/client?reload=true',
    //  'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000',
      APP_DIR + '/index.js'
      ],

  output: {
    path: path.join(__dirname, "src"),
    filename: 'bundle-hot.js'
  },
  resolve: {
    modules: [
        path.join(__dirname, 'src/'),
        'node_modules/'
    ],
    alias: {
        '~':  APP_DIR + '/images/'
    }
  },
  watch: true,
  watchOptions: {
    poll: true,
    aggregateTimeout: 300,
    number: 1000
  },
  module : {
    loaders : [
      {
        test : /\.jsx?/,
        include : APP_DIR,
        exclude: /node_modules/,
        loaders: ['react-hot-loader', 'babel-loader?' + JSON.stringify({
        cacheDirectory: true,
        plugins: [
            'transform-runtime',
            'react-html-attrs',
            'transform-class-properties',
            'transform-decorators-legacy'
        ],
        presets: ['es2015', 'react', 'stage-2']
        })]
      },
      // CSS
      // "css" loader resolves paths in CSS and adds assets as dependencies.
      // "style" loader turns CSS into JS modules that inject <style> tags.
      // In production, we use a plugin to extract that CSS to a file, but
      // in development "style" loader enables hot editing of CSS.
      {
        test: /\.css$/,
        include: path.join(__dirname, 'src/style'),
        loader: 'style-loader!css-loader'
      },
      // "file" loader makes sure those assets get served by WebpackDevServer.
      // When you `import` an asset, you get its (virtual) filename.
      // In production, they would get copied to the `build` folder.
      {
        test: /\.(ico|jpg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
        exclude: /\/favicon.ico$/,
        loader: 'file-loader',
        query: {
            name: '[path][name].[ext]'
        }
      },
      {
        test: /\.(ico)(\?.*)?$/,
        exclude: /node_modules/,
        loader: 'file-loader',
        query: {
            name: '.images/[name].[ext]'
        }
      }
    ]
  },

    // use EnableCircularDependencyPlugin=true|false to check the option
    plugins: (function() {
        var plugins = [
            new CopyWebpackPlugin([
                { from: APP_DIR + '/index.html', to: BUILD_DIR + '/index.html' },
                { from: APP_DIR + '/images/', to: BUILD_DIR + '/images/' }
            ]),
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoEmitOnErrorsPlugin(),
            new webpack.DefinePlugin({
                __DEVTOOLS__: true  // <-------- DISABLE redux-devtools HERE
            })
        ];

        // HERE IS OPTION CONDITION
        // edit .env file change to EnableCircularDependencyPlugin=false will bypass it
        if (process.env.EnableCircularDependencyPlugin=="true") {
            plugins.push(new CircularDependencyPlugin({
                // exclude detection of files based on a RegExp
                exclude: /a\.js|node_modules/,
                // add errors to webpack instead of warnings
                failOnError: true
            }));
        }

        return plugins;
    })(),
    node: {
        net: 'empty',
        dns: 'empty'
    }
};

module.exports = config;
Pic Mickael
  • 1,244
  • 19
  • 36
  • try removing the `../` from the require path – Matt Mar 17 '17 at 14:30
  • 1
    I tried that already. A path with 'images/data/NotFound.png' gives the same result. Image does not load and devtools shows a link going to http://localhost:7771/games/images/data/NotFound.png (with the extra 'games' that I am trying to get rid of) I even tried with '/images/data/NotFound.png' but in that case webpack build failed saying that it could not resolve the path. – Pic Mickael Mar 17 '17 at 14:35
  • Have you tried setting a resolve root? – Matt Mar 17 '17 at 14:38
  • webpack 2+ does not accept root. You have to used the modules instead. I even tried to put the images/data folder there, but that did not change anything. That's why I tried the alias. From my test, the alias is recognized, but the result is the same – Pic Mickael Mar 17 '17 at 14:51

1 Answers1

3

file-loader respects output.publicPath, as you've not set one, it uses the path relative to the output.path and that won't work when using a different route. To fix it just set the public path to /:

output: {
  path: path.join(__dirname, "src"),
  filename: 'bundle-hot.js',
  publicPath: '/'
},

file-loader also has an option publicPath if you don't want to set output.publicPath, as it will affect other loaders as well, but that's usually what you want and is therefore recommended. With this you'll get:

<img src="/images/data/NotFound.png">

You also don't need to copy your images directory because file-loader will copy the images you import. In fact it uses the URL to the copied file. So you should remove it from the CopyWebpackPlugin, unless you have images that are not processed by webpack.

Michael Jungo
  • 31,583
  • 3
  • 91
  • 84
  • I added the publicPath as you suggested, and the webconfig failed to build. Same error as before: Cannot resolved '/images/data/NotFound.png' in 'J:/Project/src/containers' I even tried just putting it in the file-loader and it got the same result. – Pic Mickael Mar 17 '17 at 15:25
  • That looks like you're trying to import `/images/data/NotFound.png`, but you want to import it relative to the file system and `file-loader` will generate the correct URL as output. So still do ``. – Michael Jungo Mar 17 '17 at 15:31
  • I did that. I now I have `publicPath: '/'` in the file-loader and the image src is set to `.` Yet I get the same result. the developerTools Element shows `src=images/data/NotFound.png` and when I hover it I see `http://localhost:7771/games/images/data/NotFound.png` – Pic Mickael Mar 17 '17 at 18:03
  • You have two rules that use `file-loader`, add it to the correct one or both. Or simply use the `output.publicPath`. – Michael Jungo Mar 17 '17 at 18:10
  • You got it! I added the publicPath to the wrong file-loader. Thanks a lot :) – Pic Mickael Mar 17 '17 at 18:16