Getting webpack hot updating to work correctly in my isomorphic web app
Asked Answered
K

1

7

I'm creating a webapp with a node/express backend and a react frontend. I got (I think) most of it up and running, but the last step of getting the browser to perform a hot refresh does not work as intended. I'll try to post all the relevant setup here. Please let me know if you require anything else to find out where I have done a mistake:

I start up my application with node ./server/index.js

webpack.config.js var path = require('path'); var webpack = require('webpack');

let webpackConfig = {
    name: 'server',
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: '/dist/',
    },
    resolve: {
      extensions: [
        '', '.js', '.jsx', '.json'
      ]
    },
    module: {
        loaders: [
            { 
                test: /\.(js|jsx)$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query:{
                    presets: ['es2015', 'react', 'stage-2']
                }
            },
            {
                test:  /\.json$/, 
                loader: 'json-loader'
            }
        ]
    },
    entry: [
        'webpack-hot-middleware/client',
        './app/client/client.jsx'   
    ],
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify('production')
            }
        }),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ]   
};
export default webpackConfig;

index.js just include 'babel-register' and 'server.js'

server/server.js import webpack from 'webpack'; import webpackConfig from '../webpack.config'; import webpackDevMiddleware from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware';

import express from 'express';

const app = express();
const renderPage = () => {
    return `
            <!doctype html>
            <html>
            <head>
                <title>Brewing Day</title>
                <meta charset='utf-8'>
            </head>
            <body>
                <h1>Hello from server.js!!</h1>
                <div id='root'></div>
                <script src='/dist/bundle.js'></script>
            </body>
            </html>
            `;
};

const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
    noInfo: true,
    publicPath: webpackConfig.output.publicPath })
);
app.use(webpackHotMiddleware(compiler));

app.use((req, res, next) => {
  res.status(200).end(renderPage());
});

const server = app.listen(3005, () => {
    const host = server.address().address;
    const port = server.address().port;
    console.log(`Listening at http://${host}:${port}`);
})

export default server;

And app/client/client.jsx that is the entrypoint in the webpack config:

import React from 'react';
import ReactDOM from 'react-dom';
import Application from '../components/application.jsx';

window.addEventListener('load', () => {
    ReactDOM.render(<Application />, document.getElementById('root')
    );
});

In the console, when I fire it up, it lists the following line:

webpack built cc1194a11614a3ba54a3 in 730ms

When I do a change to for example client.jsx or application.jsx that contains the rect component, I get two new lines in my console:

webpack building...
webpack built 8d340a8853d3cfe9478d in 195ms

So far, so good!

However, in the browser, it does not update and gives the following warning in console:

[HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
[HMR]  - ./app/components/application.jsx

I tried randomly adding module.hot.accept() to application.jsx. That get's rid of the warnings, but still no update without hitting F5 and reloading the browser.

Any idea what I'm missing here? I have seen another example set up almost like mine, where this works without any module.hot.accept() calls anywhere, but I fail to see where my setup differ from the other setup.

Any and all help will be appreciated.

Krauss answered 9/2, 2016 at 20:45 Comment(3)
Are you exporting your component from application.jsx?Cd
@ashwinator - Yes, the last line of my application.jsx file is export default Application;Fleischman
github.com/glenjamin/webpack-hot-middleware/issues/70Markham
K
10

After a lot of digging around, I found the answer to my problem. I was creating my base React "class" like this:

class Application = () => {
  return (
    <div id="maincontent">
      <MainMenu />
      <ScreenContents />          
    </div>
  )
};

This is unsupported for HMR, even if it's supported by React.

I had to create my class explicitly like this:

class Application extends React.Component{
  render (){
    return (
      <div id="maincontent">
        <MainMenu />
        <ScreenContents /> 
      </div>
    );
  }
};

And then HMR works just fine :)

Edit: According to @akoskm comments, it seems that the babel configuration in the webpack configuration file might be an issue as well. So here are the relevant parts:

The babel settings

var babelSettings = {
    presets: ['react', 'es2015', 'stage-2'],
    env: {
        development: {
            plugins: [
                ['react-transform', {
                    transforms: [
                        { 
                            transform: 'react-transform-hmr',
                            imports: [ 'react' ],
                            locals: [ 'module' ]
                        }
                    ]
                }]
            ]
        }
    }
};

The presets and environment stuff might not be exactly the same for you, but the react-transform stuff is the important part here.

The loader

{ 
    test: /\.(js|jsx)$/,
    loaders: ['babel?' + JSON.stringify(babelSettings)],
    exclude: /node_modules/
}
Krauss answered 15/2, 2016 at 8:23 Comment(6)
This is definitely helpful, but I think there is something more, because I'm using an almost identical way to define my base React class: github.com/archistackt/kts/blob/master/components/app.js but I'm still ending up with the same errors as you did. Do you have any idea why?Stays
@akoskm - Did you manage to solve this? In addition to the creation of the React class, I have also changed my babel loader settings in the webpack configuration. If you still need help, let me know, and we'll try to figure it out :)Fleischman
Thanks @Øyvind Bråthen. I had no chance to take a look at the project but I'll work on it in the next few days and I'll let you know if I can make it work. The repository I linked in my previous content contains the webpack config I'm using currently: github.com/archistackt/kts/blob/master/webpack.config.jsStays
I've just checked this and still doesn't work. Here is my babel loader configuration: github.com/archistackt/kts/blob/master/webpack.config.js#L22Stays
@akoskm - I added the babel settings from my project now, as they differ a lot from yours. I think that the 'react-transform-hmr' is the missing piece to your puzzle. Let me know how it turned out :)Fleischman
exactly, I missed that configuration. I wanted to ask if the documentation mentions that at all but I already found it here: github.com/gaearon/react-transform-hmr#react. However, I found the JSON.stringify(babelSettings) hackish so I included the the babelSettings as a query property: github.com/archistackt/kts/blob/master/webpack.config.js#L41. Thanks for your help!Stays

© 2022 - 2024 — McMap. All rights reserved.