Search code examples
webpackbabeljsreact-hot-loader

Why babel is not transpiling some features during react-hot-loader?


I am using transform-class-properties. When I change something like button text etc. everything works just fine, but when I modify function that look like this:

class App extends React.Component {

    fetchUser = (e) => {
        axios.get('/api/test/' + this.state.username)
            .then(function (response) {
                console.log(response.data);
            }).catch(function (response) {
            console.log(response);
        });
    };
}

There is no effect until I manually refresh the page. I see some output in the console:

[React Transform HMR] Patching App
log-apply-result.js?d762:20 [HMR] Updated modules:
log-apply-result.js?d762:22 [HMR]  - 76

But my changes aren't there until I do a refresh. This feature is working (transform-class-properties) but it is invulnerable for changes. When I add something like console.log('foobar'); and press the button nothing happens. I mean nothing new happens. When I change the syntax for normal class method syntax that ES6 understands THIS WORKS as intended, I see console.log "live" without refreshing, so I think there is something wrong during transpiling process.

This is my webpack.development.config.js file:

const webpack = require('webpack');
const path = require('path');
const NpmInstallPlugin = require('npm-install-webpack-plugin');

const PATHS = {
    app: path.join(__dirname, 'resources/assets/js'),
    publicPath: path.join(__dirname, 'public')
};

module.exports = {
    entry: [
        "webpack-dev-server/client?http://localhost:4444",
        "webpack/hot/dev-server",
        PATHS.app
    ],
    output: {
        path: PATHS.publicPath,
        publicPath: '/js/',
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                loader: "react-hot",
                exclude: /node_modules/
            },
            {
                test: /\.jsx?$/,
                include: PATHS.app,
                loader: 'babel-loader',
                query: {
                    presets: ['react', 'es2015', 'stage-0', 'react-hmre'], // set of plugins out of the box
                    plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
                }
            }
        ]
    },
    devtool: 'eval-source-map',
    devServer: {
        contentBase: PATHS.publicPath,
        historyApiFallback: true,
        hot: true,
        inline: true,
        progress: true,
        noInfo: false,
        stats: 'errors-only',
        host: process.env.HOST,
        port: 4444,
        proxy: {
            "/api/*": "http://127.0.0.1:8000/"
        }
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new NpmInstallPlugin({
            save: true
        })
    ]
};

Solution

  • This is a react-transform related problem. It patches methods just fine. The problem is that in this case fetchUser = (e) => { generates code that is more or less equal to binding at your constructor. react-transform doesn't patch constructor (run once by definition).

    Perhaps the problem will be resolved one day, but at the moment code like this just doesn't work with it. There are also issues with function based components as the setup cannot patch those yet either.

    One way to work around the issue is to push state management elsewhere and rely on standard methods when possible. Standard methods get patched just fine and you can make solutions like Redux HMR compatible easily by implementing the hot loading interface (a couple of lines of code).