Search code examples
reactjswebpackwebpack-dev-serverwebpack-hmr

can't load images when using webpack-dev-server with HMR config


I created a React project with webpack2, and previewed the result by using webpack-dev-server. At first, I just used the CLI to enable HMR as follows:

webpack-dev-server --inline --hot

everything is ok.

Then, I wanted to enable HMR by setting up webpack.config.js, but failed. The browser doesn't show me the images and the console is always show the 404 error as below:

image for error info

I looked for the methods all day and changed the config file many times, but made no difference. Any help would be great appreciate.

My project structure:

|--dist
|  |--index.html
|--src
|  |--images
|  |  |--logo.png
|  |--js
|     |--components
|     |  |--pc_header.js
|     |--index.js
|--package.json
|--webpack.config.js

package.json

"babel": {
  "presets": [
    [
      "es2015",
      {
        "modules": false
      }
    ],
    "react"
  ],
  "plugins": [
    "react-hot-loader/babel"
  ]
}

webpack.config.js

module.exports = {
context: path.resolve(__dirname, "src"),

entry: [
    'react-hot-loader/patch',
    'webpack-dev-server/client?http://localhost:8080',
    'webpack/hot/only-dev-server',  
    './index.js'
],

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

devtool: 'inline-source-map',

devServer: {
    hot: true,
    contentBase: path.resolve(__dirname, 'dist'),
    publicPath: '/'
},

module: {
    rules: [
        {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            use: [
                {
                    loader: 'babel-loader',
                    options: {
                        presets: ['react', 'es2015']        
                    }
                }
            ]
        },
        {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
              fallback: 'style-loader',
              use: 'css-loader'
            })
        },
        {
            test: /\.(png|jpe?g|svg)$/,
            use: ['file-loader?name=/img/[name].[ext]']
        }
    ]
},

plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    new ExtractTextPlugin({
        filename: 'css/[name].css'
    })
]

};

index.html

<body>
<div id="mainContainer">
</div>
<script src="bundle.js"></script>
</body> 

pc_header.js

render(){
  return (
     <img src='../../images/logo.png' alt="logo"/>
}

Maybe there's something wrong with my path config, but I have tried all kinds of path config, and use import LogoImg from "../../images/logo.png" in the file pc_header.js,all failed. Now I have no idea about this headache.


Solution

  • First in your webpack config, your file loader for images is: ['file-loader?name=/img/[name].[ext]'], which will output images to /img/name.ext

    but you are using /image/ instead.

    however, it's better to do

    import logo from '../../logo.png';

    in your components

    then

    just use it as a variable <img src={logo} alt="logo"/>

    so webpack will handle the path for you. The reason of letting webpack to handle path is you can take the advantage of keeping images by components, eg:

    |--MyComponent
    |    |-- component.js
    |    |-- images
    |        |---a.png
    |        |---b.png
    

    but when you build for production you can put all in one single folder eg assets/images

    If you feel there are too much imports, you can create a kind of index.js in images folder

    eg.

    export { default as a } from './a.png;
    export { default as b } from './b.png;
    export { default as c } from './c.png;
    

    then

    import {a, b, c } from './images';