如何让 react-hot-loader 与 webpack 2 和 webpackDevMiddleware 一起工作?
Posted
技术标签:
【中文标题】如何让 react-hot-loader 与 webpack 2 和 webpackDevMiddleware 一起工作?【英文标题】:How to get react-hot-loader working with webpack 2 and webpackDevMiddleware? 【发布时间】:2017-07-06 07:04:56 【问题描述】:我使用的是 express 中间件而不是 webpack-dev-server:
const config = require("../webpack.config.js");
if(process.env.NODE_ENV === 'development')
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler,
stats: colors: true,
));
app.use(webpackHotMiddleware(compiler));
我已经从react-hot-loader@3
尝试了react-hot-loader/patch
、react-hot-loader/babel
和react-hot-loader/webpack
:
module.exports =
context: path.join(__dirname, 'client'),
entry: [
'webpack-hot-middleware/client',
'react-hot-loader/patch',
'./entry.less',
'./entry',
],
output:
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/',
,
module:
rules: [
test: /\.jsx/,
use: [
loader: 'babel-loader',
options:
plugins: ['transform-react-jsx', 'transform-class-properties', 'react-hot-loader/babel'],
,
,
'react-hot-loader/webpack'
],
,
但它们似乎都不起作用。我刚刚收到此错误消息:
[HMR] 以下模块无法热更新:(需要完全重新加载) 这通常是因为已更改的模块(及其父模块)不知道如何自行热重载。有关详细信息,请参阅http://webpack.github.io/docs/hot-module-replacement-with-webpack.html。 日志更新@bundle.js:29964 应用回调@bundle.js:29932 (匿名)@ bundle.js:29940 bundle.js:29972 [HMR] - ./client/components/CrawlForm.jsx
让它发挥作用的诀窍是什么?
注意CSS 热加载工作得很好,所以我得到了那部分工作。
【问题讨论】:
【参考方案1】:我花了好几天才终于破案。这是我的有效代码:
Webpack 配置对象
const clientConfig =
entry:
client: [
'react-hot-loader/patch',
'webpack-hot-middleware/client',
'babel-polyfill',
'./src/client/client.js',
],
,
output:
path: path.resolve(__dirname, './build/public'),
filename: '[name].js',
publicPath: '/',
,
devtool: 'inline-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.LoaderOptionsPlugin(
debug: true,
),
new CopyWebpackPlugin([
from: './src/assets/fonts', to: 'fonts' ,
from: './src/assets/images', to: 'images' ,
]),
new webpack.EnvironmentPlugin(['GOOGLE_MAP_API_KEY']),
],
module:
rules: [
test: /(\.js|\.jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/,
options:
presets: [['es2015', loose: true ], 'react', 'stage-2'],
,
,
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
],
,
],
,
;
服务器 index.js
我和你一样使用开发中间件和热中间件。我还从 react-hot-loader 导入 AppContainer
并包装我的组件。
import express from 'express';
import React from 'react';
import routes from 'components/Routes';
import html from './html';
import renderToString from 'react-dom/server';
import match, RouterContext from 'react-router';
import Provider from 'react-redux';
import makeStore from 'store';
import Immutable from 'immutable';
import setupNameless from './setupNameless';
import db from './database';
import actions from '../client/constants';
import webpack from 'webpack';
import webpackHotMiddleware from 'webpack-hot-middleware';
import webpackDevMiddleware from 'webpack-dev-middleware';
import clientConfig as wpConfig from '../../webpack.config.js';
import AppContainer from 'react-hot-loader';
import dotenv from 'dotenv';
dotenv.config();
const compiler = webpack(wpConfig);
db();
const app = express();
app.use(webpackDevMiddleware(compiler,
publicPath: wpConfig.output.publicPath,
// noInfo: true,
stats:
colors: true,
,
));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('build/public'));
const commander: nameless, apiPrefix = setupNameless(app);
app.use((req, res, next) =>
// make DB call here to fetch jobs.
nameless.exec('jobs', actions.GET_JOBS).then((jobs) =>
const store = makeStore(Immutable.fromJS(
// filters: ,
app:
apiPrefix,
search:
query: '',
options: ,
,
,
jobs,
));
match(
routes,
location: req.originalUrl,
, (error, redirectLocation, renderProps) =>
if (error)
res.status(500).send(error.message);
else if (redirectLocation)
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
else if (renderProps)
// You can also check renderProps.components or renderProps.routes for
// your "not found" component or route respectively, and send a 404 as
// below, if you're using a catch-all route.
try
res.status(200).send(html(renderToString(
<AppContainer>
<Provider store=store>
<RouterContext ...renderProps />
</Provider>
</AppContainer>
), store.getState()));
catch (err)
next(err);
else
res.status(404).send('Not found');
);
, (e) =>
next(e);
).catch(e =>
next(e);
);
);
app.use(logErrors);
function logErrors(err, req, res, next)
console.error(err.stack);
next(err);
app.listen(process.env.PORT || 3000, () =>
console.log(`App listening on port $process.env.PORT || 3000`);
);
Client.js
这就是让它发挥作用的魔力。我必须添加 if (module.hot)
代码并从 react-hot-loader 导入 AppContainer
。另一个重要方面是将key=Math.random()
添加到我的<Router />
组件中。
import match, Router, browserHistory as history from 'react-router';
import routes from './components/Routes';
import ReactDOM from 'react-dom';
import React from 'react';
import Provider from 'react-redux';
import makeStore from './store';
import Immutable from 'immutable';
import createLogger from 'redux-logger';
import createSagaMiddleware from 'redux-saga';
import sagas from './sagas';
import AppContainer from 'react-hot-loader';
const logger = createLogger();
const sagaMiddleware = createSagaMiddleware();
const store = makeStore(
Immutable.fromJS(window.__INITIAL_STATE__),
logger,
sagaMiddleware
);
sagaMiddleware.run(sagas);
ReactDOM.render(
<AppContainer>
<Provider store=store>
<Router history=history routes=routes />
</Provider>
</AppContainer>,
document.getElementById('app'));
if (module.hot)
module.hot.accept('./components/Routes', () =>
const nextRoutes = require('./components/Routes').default;
ReactDOM.render(
<AppContainer>
<Provider store=store>
<Router key=Math.random() history=history routes=nextRoutes />
</Provider>
</AppContainer>,
document.getElementById('app'));
);
祝你好运?
【讨论】:
哇...这比以前复杂多了。<AppContainer>
和 if(module.hot)
位对我有用。谢谢!!【参考方案2】:
转述Dan Abramov 并借用realseanp 的部分代码,完整说明如下:
yarn add react-hot-loader@3
更新webpack.config.js
:
-
将
react-hot-loader/patch
和webpack-hot-middleware/client
添加到entry
的顶部
将react-hot-loader/babel
添加到您的babel-loader
plugins
将new HotModuleReplacementPlugin()
添加到您的 webpack 插件中
加webpack-dev-middleware
和webpack-hot-middlware
表示:
// server/entry.jsx
const express = require('express');
const path = require('path');
const cons = require('consolidate');
const fs = require('fs');
const port = 5469;
const app = express();
app.disable('x-powered-by');
app.engine('hbs', cons.handlebars);
app.set('view engine', 'hbs');
app.set('views', path.join(__dirname, '../views'));
const wpConfig = require("../webpack.config.js");
if(process.env.NODE_ENV === 'development')
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const compiler = webpack(wpConfig);
app.use(webpackDevMiddleware(compiler,
stats: colors: true,
));
app.use(webpackHotMiddleware(compiler));
app.use(require('./routes'));
app.use(express.static(wpConfig.output.path));
app.listen(port, function ()
console.log(`Listening on http://localhost:$port`);
);
将<AppContainer>
和react.hot
添加到您的客户端入口点:
// client/entry.jsx
import ReactDOM from 'react-dom';
import App from './components/App';
import AppContainer from 'react-hot-loader';
function render(Root)
ReactDOM.render(<AppContainer><Root/></AppContainer>, document.getElementById('react-root'));
render(App);
if(module.hot)
module.hot.accept('./components/App', () =>
render(require('./components/App').default);
);
【讨论】:
【参考方案3】:我在获取错误叠加层以呈现运行时错误以及从中恢复时遇到了一些麻烦。我注意到webpack-dev-server
在发生错误时会完全重新加载。
这可以用下面的sn-p来模拟:
if (module.hot) module.hot.accept('./App', () =>
try
render(App)
catch (e)
location.reload();
);
我的工作 fork of react-hot-boilerplate 可以在 Github 上找到。
【讨论】:
【参考方案4】:我还在我的应用程序中添加了每个点,但它没有用
问题出在我的webpack.config.js
中的publicPath
我有
publicPath: '/client/dist'
然后我改成
publicPath: '/'
现在它可以工作了
【讨论】:
以上是关于如何让 react-hot-loader 与 webpack 2 和 webpackDevMiddleware 一起工作?的主要内容,如果未能解决你的问题,请参考以下文章
无法让多应用 webpack 配置与 react-hot-loader 一起使用
react-hot-loader 与外部 configureStore 使用 redux-saga 抛出“regeneratorRuntime 未定义”
无法使 react-hot-loader 和 webpack-dev-server 与 react-router 一起工作