升级到Webpack2坑——模块热替换失效页面不自动刷新?

问题:

升级 Webpack1 到 Webpack2 之后, 开发模式下实时重载(Live Reloading)不起作用。控制台一直显示“App hot update...”。页面不自动刷新,没有变化。

一直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
  • webpack2.7.0
  • react-hot-loader1.3.0
  • webpack-dev-server1.14.1
  • django-webpack-loader0.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

升级到Webpack2坑——模块热替换失效页面不自动刷新?_第1张图片
需要升级react-hot-loader

提问者还总结了解决方法,其中第一点,升级 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-loaderwebpack-dev-server

注意,这个项目升级前HMR是启用的,配置参考django-webpack-loader example,升级过程中没有改动 webpack 的配置,只是根据 v2 的新特性做了相应的用法上的改变(详情参考迁移到新版本)。因此下面的内容不是从0到1地配置 HMR,而是一个升级(主要react-hot-loader)的过程。

  1. npm升级react-hot-loader到v3或v4,升级webpack-dev-server到v2。
    "react-hot-loader": "^4.0.0",
    "webpack-dev-server": "^2.3.0"
    
  2. 在.babelrc 文件的plugins中添加一项:"react-hot-loader/babel"
  3. 修改 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']
      }
    );
    
  4. 修改 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');
    });
    
  5. 使用 react-hot-loaderAppContainer封装应用的顶底组件。可参考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(
        
          
        ,
        document.getElementById('root')
      )
    }
    render(Root)
    if (module.hot) {
      module.hot.accept('./containers/Root', () => { render(Root)})
    }
    

按道理,到这为止react-hot-loader的升级就完成了。HMR应该就生效了。但是我又遇到一个坑,浏览器控制台的输出信息都正常,新的打包文件的网络请求也正常,但是页面上却依然没变化。又是坑啊!最后在Hot updates not applied #581里面找到相同情况的解决方法。

升级到Webpack2坑——模块热替换失效页面不自动刷新?_第2张图片
热更新依然不生效

效果图:


升级到Webpack2坑——模块热替换失效页面不自动刷新?_第3张图片
热更新

结语

这个问题的解决过程中踩了不少坑,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

你可能感兴趣的:(升级到Webpack2坑——模块热替换失效页面不自动刷新?)