使用React-hot-loader 3,React-router 4和Webpack-hot-middleware来实现Hot Reload

时间:2017-08-14 15:56:07

标签: reactjs webpack webpack-hmr

我正在努力让React-hot-loader 3与React-hot-loader 3,React-router 4和Webpack-hot-middleware(最新版本,2.18.2)协同工作。

这是我的select concat(p.PageName, C.CategoryName, PD.ProductName) AS Content from ...

server.js

我的const express = require('express'); const bodyParser = require('body-parser'); const cookiesMiddleware = require('universal-cookie-express'); /* eslint-disable import/no-extraneous-dependencies */ const webpack = require('webpack'); const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); const webpackHotServerMiddleware = require('webpack-hot-server-middleware'); /* eslint-enable import/no-extraneous-dependencies */ const clientConfig = require('./webpack.config.dev.client'); const serverConfig = require('./webpack.config.dev.server'); const PORT_NUMBER = process.env.PORT || 3000; const app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(cookiesMiddleware()); app.use(express.static('public')); const multiCompiler = webpack([clientConfig, serverConfig]); const clientCompiler = multiCompiler.compilers[0]; app.use(webpackDevMiddleware(multiCompiler, { publicPath: clientConfig.output.publicPath, noInfo: true, stats: { children: false }, })); app.use(webpackHotMiddleware(clientCompiler)); app.use(webpackHotServerMiddleware(multiCompiler, { serverRendererOptions: { outputPath: clientConfig.output.path }, })); app.listen(PORT_NUMBER, () => { // eslint-disable-next-line no-console console.log(`Server listening at port ${PORT_NUMBER}`); });

client entry point

import React from 'react'; import { render } from 'react-dom'; import { AppContainer } from 'react-hot-loader'; import * as Bundles from './components/Bundles'; import App from './App'; const doRender = () => { render( <AppContainer> <App type="client" /> </AppContainer>, document.getElementById('content'), ); }; const splitPoints = window.splitPoints || []; Promise.all(splitPoints.map(chunk => Bundles[chunk].loadComponent())) .then(doRender); if (module.hot) { module.hot.accept('./App', doRender); }

.babelrc

看起来我遵循react-hot-loader's README的每一步,但每次我更改组件中的某些代码时,我都会在控制台中收到此消息:

{
  "plugins": [
    "transform-decorators-legacy",
    "transform-object-rest-spread"
  ],
  "presets": [
    ["es2015", { "modules": false }],
    "react",
    "stage-0"
  ],
  "env": {
    "development": {
      "plugins": ["react-hot-loader/babel"]
    },
    "test": {
      "plugins": ["transform-es2015-modules-commonjs"]
    }
  }
}

有人偶然发现了这个吗?提前谢谢!

编辑:这是我的客户端webpack配置:

[HMR] bundle rebuilding
client.js:207 [HMR] bundle rebuilt in 8218ms
process-update.js:27 [HMR] Checking for updates on the server...
process-update.js:81 [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.

1 个答案:

答案 0 :(得分:1)

也许它与你的webpack.config文件有关?你在参赛作品中设置了热门的东西吗?

const config = {
    entry: [
        'babel-polyfill',

        'react-hot-loader/patch', // activate HMR for React
        `webpack-hot-middleware/client?path=http://${HOST}:${PORT}/__webpack_hmr`, // bundle the client for webpack-hot-middleware and connect to the provided endpoint

        './src/client.jsx',
    ],

我有更好的运气使用Hapi作为我的服务器与webpack-hot-middleware和webpack-dev-middleware。这是一个片段

import Webpack from 'webpack';
import HapiWebpackPlugin from 'hapi-webpack-plugin';

const config = require('../../../webpack.config.js'); // eslint-disable-line global-require
const compiler = Webpack(config);

const options = {
    assets: {
        // webpack-dev-middleware options - https://github.com/webpack/webpack-dev-middleware
        index: '/public/index.html',
    },
    hot: {
        // webpack-hot-middleware options - https://github.com/glenjamin/webpack-hot-middleware
    },
    compiler,
};

server.register({
    register: HapiWebpackPlugin,
    options,
}, (error) => {
    if (error) {
        console.error(error);
    }
});

如果您想尝试Hapi,请查看我的hapi-react-hot-loader-example

这是我的完整webpack.config

const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const RobotstxtPlugin = require('robotstxt-webpack-plugin').default;

const PORT = process.env.PORT || 3000;
const HOST = process.env.HOST || 'localhost';
const NODE_ENV = process.env.NODE_ENV || 'production';
const isProduction = (NODE_ENV === 'production');
const isDevelopment = (NODE_ENV === 'development');

const config = {
    entry: isDevelopment
        ? [
            'babel-polyfill',

            'react-hot-loader/patch', // activate HMR for React
            `webpack-hot-middleware/client?path=http://${HOST}:${PORT}/__webpack_hmr`, // bundle the client for webpack-hot-middleware and connect to the provided endpoint

            './src/client.jsx',
        ]
        : [
            'babel-polyfill',

            './src/client.jsx',
        ],

    resolve: {
        extensions: ['.js', '.jsx', '.json'],
    },

    output: {
        path: path.join(__dirname, 'dist/public/'),
        filename: isDevelopment
            ? 'main.js'
            : 'assets/scripts/[name].[chunkhash].js',
    },

    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['css-hot-loader'].concat(
                    ExtractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: [
                            {
                                loader: 'css-loader',
                                options: {minimize: true},
                            },
                            {
                                loader: 'postcss-loader',
                            },
                        ],
                    })
                ),
            },
            {
                test: /\.jsx?$/,
                use: ['babel-loader'],
                include: path.join(__dirname, 'src'),
            },
        ],
    },

    plugins: [
        new ProgressBarPlugin(),

        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
        }),

        isDevelopment
            ? null
            : new webpack.optimize.ModuleConcatenationPlugin(),

        isDevelopment
            ? new webpack.HotModuleReplacementPlugin() // enable HMR globally
            : null,
        isDevelopment
            ? new webpack.NamedModulesPlugin() // prints more readable module names in the browser console on HMR updates
            : null,
        isDevelopment
            ? new webpack.NoEmitOnErrorsPlugin() // do not emit compiled assets that include errors
            : null,

        new ExtractTextPlugin({
            filename: isDevelopment
                ? 'assets/styles/main.css'
                : 'assets/styles/[name].[chunkhash].css',
        }),

        isDevelopment
            ? null
            : new webpack.optimize.CommonsChunkPlugin({
                name: 'vendor',
                minChunks: module => /node_modules/.test(module.resource),
            }),

        isDevelopment
            ? null
            : new webpack.optimize.CommonsChunkPlugin({name: 'manifest'}),

        isProduction
            ? new webpack.optimize.UglifyJsPlugin()
            : null,

        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, 'src/index.html'),
            minify: isProduction ? {collapseWhitespace: true, collapseInlineTagWhitespace: true} : false,
            alwaysWriteToDisk: true,
        }),
        new HtmlWebpackHarddiskPlugin(),

        new CopyWebpackPlugin([
            {
                context: 'src/assets/media',
                from: '**/*',
                to: 'assets/media',
            },
        ]),

        new RobotstxtPlugin({
            policy: [
                isProduction
                    ? {userAgent: '*', allow: '/'}
                    : {userAgent: '*', disallow: '/'},
            ],
        }),
    ].filter(Boolean),

    devtool: isProduction
        ? 'none'
        : 'cheap-module-eval-source-map',

    performance: {
        maxAssetSize: 500000,
    },
};

module.exports = config;