问题:
升级 Webpack1 到 Webpack2 之后, 开发模式下实时重载(Live Reloading)不起作用。控制台一直显示“App hot update...”。页面不自动刷新,没有变化。
解决办法:
去掉。WebpackDevServer
配置中的hot:true
new WebpackDevServer(webpack(config), {
......
// hot: true, //去掉
inline: true,
......
})
不过不知道为什么得去掉...
以下内容更新于2018/05/15
以上的方法其实没有解决根本问题。当时只知道去掉
hot:true
配置后,修改文件时页面能够自动刷新了,但不知道为什么这么做,问题到底在哪里。近期看到留言才重新研究了这个问题。花费了好几个小时踩坑,算是对这个问题有了新的认识。
项目结构是,django + react + webpack。
版本:
-
react
:0.14.7
-
webpack
:2.7.0
-
react-hot-loader
:1.3.0
-
webpack-dev-server
:1.14.1
-
django-webpack-loader
:0.5.0
值得参考的样板项目:
-
django-webpack-loader example(
webpack v1
+webpack-dev-server v1
+react-hot-loader v1
)
升级webpack 之前,我项目的配置跟这个例子差不多。 -
react-hot-loader-minimal-boilerplate (
webpack v2
+webpack-dev-server v2
+react-hot-loader v3
)
问题
升级 webpack
v1到v2之后,模块热替换(Hot Module Replacement,HMR)失效了,而 webpack 配置的entry
中'webpack/hot/only-dev-server'
指明了HMR失效时,页面也不会重新加载(参考What's the difference between 'webpack/hot/dev-server' and 'webpack/hot/only-dev-server'?),所以开发模式下修改文件,页面不会自动刷新。
模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:
- 保留在完全重新加载页面时丢失的应用程序状态。
- 只更新变更内容,以节省宝贵的开发时间。
- 调整样式更加快速 - 几乎相当于在浏览器调试器中更改样式。
解决办法
如果不需要HMR,只需要页面可以自动刷新,那可以去掉WebpackDevServer
配置中的hot:true
或者把 webpack 配置的entry
中'webpack/hot/only-dev-server'
改成'webpack/hot/dev-server'
。这样就算HMR 不生效,也不影响开发过程中实时看到页面的变化。
但升级webpack
v1到v2之后,还是想使用HMR呢?
Webpack
升级到2.7.0
之后,react-hot-loader
还是v1,根据 react-hot-loader v1.3.0 stopped working after upgrade to webpack 2.2.1 #474 中的讨论,说明需要升级react-hot-loader
,v1应该是不适用 webpack v2
。
提问者还总结了解决方法,其中第一点,升级
webpack
时也要升级webpack-dev-server
。
Make sure your webpack-dev-server AND webpack are both updated. at time of writing this is what i've got
"react-hot-loader": "^3.0.0-beta.6", "webpack-dev-server": "^2.3.0", "webpack": "^2.2.1",
以上说明,重点是要升级react-hot-loader
和webpack-dev-server
。
注意,这个项目升级前HMR是启用的,配置参考django-webpack-loader example,升级过程中没有改动 webpack 的配置,只是根据 v2 的新特性做了相应的用法上的改变(详情参考迁移到新版本)。因此下面的内容不是从0到1地配置 HMR,而是一个升级(主要
react-hot-loader
)的过程。
-
npm
升级react-hot-loader
到v3或v4,升级webpack-dev-server
到v2。"react-hot-loader": "^4.0.0", "webpack-dev-server": "^2.3.0"
- 在.babelrc 文件的
plugins
中添加一项:"react-hot-loader/babel"
。 - 修改 webpack 配置。
//webpack.config.local.js //1.修改入口 var config = require('./webpack.base.config.js'); config.entry.app = [ 'webpack-dev-server/client?http://' + ip + ':3000', 'webpack/hot/only-dev-server', //dev-server reloads when applying HMR fails, only-dev-server doesn't. 'react-hot-loader/patch', //添加这一项 './html/app', ] //2.去掉react-hot-loader config.module.rules.push( { test: /\.jsx?$/, exclude: /node_modules/, use: ['babel-loader'] //before: ['react-hot-loader','babel-loader'] } );
- 修改
WebpackDevServer
的配置。添加headers
。详情参考React Hot Loader Troubleshooting 。//server.js new WebpackDevServer(webpack(config), { publicPath: config.output.publicPath, hot: true, //enable HMR on the server headers:{'Access-Control-Allow-Origin':'*'}, //添加这一项 inline: true, historyApiFallback: true }).listen(3000, 'localhost', function (err, result) { if (err) { console.log(err); } console.log('Listening at localhost:3000'); });
- 使用
react-hot-loader
的AppContainer
封装应用的顶底组件。可参考react-hot-loader-minimal-boilerplate。import React from 'react' import ReactDOM from 'react-dom' import { AppContainer } from 'react-hot-loader' import Root from './containers/Root' const render = Component => { ReactDOM.render( <AppContainer> <Component /> </AppContainer>, document.getElementById('root') ) } render(Root) if (module.hot) { module.hot.accept('./containers/Root', () => { render(Root)}) }
按道理,到这为止react-hot-loader
的升级就完成了。HMR应该就生效了。但是我又遇到一个坑,浏览器控制台的输出信息都正常,新的打包文件的网络请求也正常,但是页面上却依然没变化。又是坑啊!最后在Hot updates not applied #581里面找到相同情况的解决方法。
效果图:
结语
这个问题的解决过程中踩了不少坑,webpack官方文档只提供了v4版本的,很多人也都在吐槽看不到历史版本的文档。这个对开发者来说确实很不方便。非官方的文档有很多,但却加大了排错过程花费的精力,降低了效率。
毕竟升级webpack还是挺麻烦的,v1到v2还好,变化不多,升级到v3配置就改变很多了。并且一些相关插件也得升级,比如这次没有升级react-hot-loader
就出问题了。至于那些插件该一起升级也没个官方说法,只能出问题了再疯狂地Google。
吐槽归吐槽,坑再多,还是得踩啊~~~
延伸阅读:
- 这篇关于Webpack热加载的文章讲的很清晰透彻!虽然示例用的是Webpack1
Webpack’s HMR & React-Hot-Loader — The Missing Manual:
https://medium.com/@rajaraodv/webpacks-hmr-react-hot-loader-the-missing-manual-232336dc0d96 - Difference between
new webpack.HotModuleReplacementPlugin()
and--hot
?:
https://github.com/webpack/webpack-dev-server/issues/97 - Webpack 2 配置 React 热加载,React Hot Loading with Webpack 2:
http://engineering.monsanto.com/2017/08/15/react-hotloading-with-webpack-2/ - “module not found : Error: Cannot resolve module 'react/lib/ReactMount' ”:
https://stackoverflow.com/questions/40652327/module-not-found-error-cannot-resolve-module-react-lib-reactmount - 升级React Hot Loader,可参考 Update TodoMVC example to React Hot Loader 3:
https://github.com/reduxjs/redux-devtools/commit/64f58b7010a1b2a71ad16716eb37ac1031f93915 - 使用React Hot Loader 的问题及解决方法 :
https://github.com/gaearon/react-hot-loader/blob/master/docs/Troubleshooting.md