前言

在用 react-hot-loader v1.3 的时候有些深层组件不会很完美的热更新(可能是我使用有问题)。然后在 react-hot-loader 首页中看到 React Hot Loader 3 is on the horizon,便想换成这个,结果就开启了一周的踩坑之路...

模块依赖

务必升级最新的 React-Hot-Loader v3.0.0-beta.3 
这版修复了错误栈无法跟踪到内层组件的问题,否则内部组件报错只能追溯到 AppContainer。

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `AppContainer`.
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `AppContainer`.


截止 2016-08-08 00:00,依赖模块的版本分别是:

webpack ^1.13.1
webpack-dev-server ^1.14.1
react-hot-loader ^3.0.0-beta.2
babel-core ^6.13.2
babel-loader ^6.2.4

注:我没有用到 Redux。

升级方法

因为目前 React Hot Loader 3 还在测试阶段,没有文档,所以需要在 gaearon/react-hot-boilerplate#61 这个 issue 中提到的两个 commit 中查看升级方法:

  • Update TodoMVC example to React Hot Loader 3
  • Bump to 3.0.0-beta.0

下面我来总结一下,具体要做哪些改动:

1. 安装 React Hot Loader 3

Bash
$ npm install --save-dev react-hot-loader@^3.0.0-beta.2

2. 修改 .babelrc

在 .babelrc 中添加 react-hot-loader/babel 插件

JSON
{"presets": ["es2015", "react"], "plugins": ["react-hot-loader/babel"] } 

需要注意的一点是,.babelrc 配置不需要再分 dev 环境:

JSON
..."env": {"development": { "plugins": ["react-hot-loader/babel"] } } ... 

因为作者已经在 react-hot-loader 模块中加了 process.env.NODE_ENV 判断,因此它不会在生产环境运行。

3. 修改入口及路由组件

以 React + React-Router 为例,目录结构如下:

Bash
singlePageView
├── config
│   ├── App.jsx    # 渲染 <Router>
│   ├── Routes.js  # routes
│   └── config.js
├── index.html
├── index.jsx      # 入口文件
└── views          # 单页 views├── application│   ├── Home│   │   └── index.jsx│   └── Layout│       ├── Header.jsx│       ├── Menu.jsx│       └── index.jsx└── users ├── Business └── Employee └── index.jsx 
a) 入口 index.jsx:
React JSX
// index.jsx
// 增加 AppContainer
import { AppContainer } from 'react-hot-loader' import React from 'react' import { render } from 'react-dom' // <Router> 放在 ./config/App.jsx 中 import App from './config/App' const appElem = document.querySelector('#app') // 给原来的 <App /> 包裹一层 AppContainer render( <AppContainer> <App /> </AppContainer>, appElem ) if (module.hot) { // If you use Webpack 2 in ES modules mode, you can // use <App /> here rather than require() a <NextApp />. // 如果用 ES 模块模式的 Webpack 2,可以直接用 <App /> module.hot.accept('./config/App', () => { const NextApp = require('./config/App').default render( <AppContainer> <NextApp /> </AppContainer>, appElem ) }) } 
b) ./config/App.jsx:
React JSX
// App.jsx
import React, { Component } from 'react' import { browserHistory, Router } from 'react-router' import routes from './Routes' export default class App extends Component { render () { return <Router history={browserHistory} routes={routes} /> } } 
c) ./config/Routes.js

这里我用了 webpack 的 code splitting (require.ensure),因此必须用 routes 的对象形式,而不是 JSX。

JavaScript
// Routes.js
import Layout from '../views/application/Layout' import Home from '../views/application/Home' const routes = { path: '/manage-admin', component: Layout, indexRoute: { component: Home }, childRoutes: [{ path: 'users/employee', getComponent (nextState, cb) { require.ensure([], require => { const Employee = require('../views/users/Employee') /** * 注意:babel 6 不再暴露默认的 `module.exports` * 可以使用 babel-plugin-add-module-exports 插件 * 或者像下面这样直接使用 Module.default */ cb(null, Employee.default) }) } }] } export default routes 

4. 修改 webpack.dev.config.js

因为在 .babelrc 中加上了 react-hot-loader/babel 插件,针对 js/jsx 的 loaders 可以去掉 'react-hot':

JavaScript
// ...
loaders: [{ test: /\.jsx?$/i, // loaders: ['react-hot', 'babel'], loaders: ['babel'], exclude: /(node_modules|bower_components)/ } // ... 

注意点: 在 entry 中要加上 react-hot-loader/patch 这个脚本,而且必须先于页面引用的 JS 文件之前运行。 
比如,我一个单页有 vendor.js & entry.js 最先加载的是 vendor,因此必须放在 vendor 最前面引用 react-hot-loader/patch,否则放到 entry 中,是无法进行热更新的。

错误示范:

JavaScript
// ...
entry: {  vendor: ['react', 'react-dom', 'react-router', 'react-tap-event-plugin', 'babel-polyfill'], 'manage-admin': [ 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/only-dev-server', // patch放在这里无效,因为 vendor 最先加载,且包含 react 'react-hot-loader/patch', './src/views/manage-admin/index.jsx' ] }, // ... 

正确方法:

JavaScript
// ...
entry: {  // patch 要放在 vendor 最前面 vendor: ['react-hot-loader/patch', 'react', 'react-dom', 'react-router', 'react-tap-event-plugin', 'babel-polyfill'], 'manage-admin': [ 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/only-dev-server', './src/views/manage-admin/index.jsx' ] }, // ... 

按照 issue 中配置修改到此结束,下面介绍一些解决遗留问题的黑科技

遗留问题

根据 https://github.com/gaearon/react-hot-boilerplate/pull/61 其中 @dferber90 巨巨提出的解决方案整理

1. 避免 react-hot-loader 失效

所有的组件必须用 const 来定义的,避免组件引用被修改,否则会使 react-hot-loader 失效。

2. 避免 react-router 输出报错信息

这个版本 react-router 和 react-hot-loader 3 不太兼容,在每次热更新时 react-router 会报错: Warning: [react-router] You cannot change <Router routes>; it will be ignored 
虽然不影响热更新,但有个报错还是很影响开发的。

可以通过引入一个空对象,用 Object.assign 合并 routes 到空对象上,避免「change <Router routes>」:

创建 ./config/referentially-equal-root-route.js

JavaScript
// referentially-equal-root-route.js
export default {} 
React JSX
// Routes.js
// ...
import routeSource from './Routes' import referenctiallyEqualRootRoute from './referentially-equal-root-route' const routes = Object.assign(referenctiallyEqualRootRoute, routeSource) render () { return <Router routes={routes} /> } // ... 

这样修改以后, react-router 的报错便不再出现了。

3. 为异步(Code Splitting)路由组件提供热更新

异步路由组件在修改代码后,看控制台显示热更新完成,但组件却没有变化,除非重新加载一遍这个异步组件(后退前进 或 从别的路由路径切换到这个更新的路由路径),才会更新。

(这个解决方法略微蛋疼)

在 ./config/Routes.js 中我们只要引用任何异步模块:

JavaScript
// ...
getComponent (nextState, cb) { require.ensure([], require => { const Employee = require('../views/users/Employee') cb(null, Employee.default) }) } // ... 

都需要在 ./config/App.jsx (即 Root 组件) 中 require 一遍:

React JSX
// ...
if (process.env.NODE_ENV !== 'production') { // ... 有多少异步模块就 require 多少 require('../views/users/Employee') } export default class App extends Component { render () { return <Router history={browserHistory} routes={routes} /> } } 

这样才能在开发环境中,对异步模块进行热更新。 
(记得在 npm run build 脚本命令中加上 NODE_ENV=production

最后

上述代码均在开发和生产环境下测试通过,如果有问题,可以在下方 Disqus 评论中问我,或者直接看 https://github.com/gaearon/react-hot-boilerplate/pull/61 里的内容找解决办法。

遗留问题如果没遇到可以不用解决,React Hot Loader 3 正式出来后这些问题应该都不存在了...

转载于:https://www.cnblogs.com/chris-oil/p/8454611.html

[转] React Hot Loader 3 beta 升级指南相关推荐

  1. 打算升级到 Monterey?我们为你准备了一份 macOS 安全升级指南

    2021 年 10 月 26 日,期待已久的 macOS 12 正式版终于发布.苹果公司选用加州风景秀丽的小城 Monterey 作为此版本的名字.在外观上, macOS Monterey 并没有大的 ...

  2. [转] PyTorch 0.4新版本 升级指南 no_grad

    转自PyTorch 0.4新版本 升级指南,博主为ShellCollector. PyTorch 0.4新版本 升级指南 PyTorch 终于从0.3.1升级到0.4.0了, 首先引入眼帘的,是PyT ...

  3. 005-Sencha Cmd 5升级指南

    Sencha Cmd 5升级指南 本指南旨在帮助开发人员使用Sencha Cmd从ExtJS 4.1.1 a+升级到ExtJS 5.0.x. 尽管在这个版本中有一些重要的变化,但是我们已经尝试使升级过 ...

  4. react 动态修改路由_升级到 React Router 4 并实现动态加载和模块热替换

    这篇文章是升级到Webpack2坑--模块热替换失效页面不自动刷新?的后续.那篇文章主要说明了,升级到 Webpack 2 之后,通过升级webpack-dev-server和react-hot-lo ...

  5. 小米9什么时间升级android10,小米9/MIX 3 现在即可升级安卓10.0!升级指南戳这里...

    原标题:小米9/MIX 3 现在即可升级安卓10.0!升级指南戳这里 [手机频道·原创] 最近小米接连有消息爆出,在今天早些时候的I/O开发者大会上,谷歌在Android Q中推出了许多新功能.现在, ...

  6. React Native 项目整合 CodePush 完全指南

    作者 | 钱凯 杏仁移动开发工程师,前嵌入式工程师,关注大前端技术新潮流. 本文使用的环境: React@16.3.1 React Native@0.55.4 react-native-code-pu ...

  7. PyTorch 0.4新版本 升级指南 no_grad

    PyTorch 0.4新版本 升级指南 [导读]今天大家比较关心的是PyTorch在GitHub发布0.4.0版本,专知成员Huaiwen详细讲解了PyTorch新版本的变动信息, 本次升级, 只做了 ...

  8. San CLI 4.0 升级指南

    San CLI 历经多个版本迭代,目前已经进入 4.0 版本,增加 webpack5 支持.优化配置机制等,本文会对升级经验做出总结,期望给读者带来一些启发. 前言 San CLI 更新到 3.0 版 ...

  9. composer升级_Composer 使用姿势与 Lumen 升级指南

    Composer 使用姿势 这里主要说说 composer.json 和 composer.lock 文件的作用. composer.json composer.json 文件包含了项目的依赖和其它的 ...

最新文章

  1. linux ssh 设置的相关总结(ssh最大连接数、ssh连接时长、安全性配置等)
  2. matlab随机数生成
  3. Java循环案例-银行存钱问题
  4. ❤️时间管理大师!我是如何规划自己的时间的?充分利用每一分一秒!❤️
  5. 数据库连接池性能比对(hikari druid c3p0 dbcp jdbc)
  6. 解调去载波后均衡信道与实际信道的关系
  7. DBMS-数据库设计与E-R模型:E-R模型、约束、E-R图、E-R扩展特性、E-R图转换为关系模式、UML建模...
  8. 程序猿 自己所擅长的还是码代码 请远离 业务。
  9. 【opencv有趣应用】图像拼图
  10. listView基本实现
  11. vscode + SFTP 传输文件到服务器,从服务器下载文件
  12. 深入理解jQuery中的Deferred
  13. GitHub无法push的问题
  14. 一个好用的不基于时间的同步文件的软件 —— Allway sync 文件同步
  15. 如何批量删除Word中向下箭头的符号
  16. 公众号添加跳转网页链接
  17. Matlab利用textread或者textscan读取格式化txt文件
  18. QQ登录界面测试用例设计:
  19. what is a rx ring/tx ring in router?
  20. Office - - Excel宏录制批量处理格式相同文件

热门文章

  1. IAR for msp430 MDK中 warning: #223-D: function xxx declared implicitly 解决方法
  2. Hadoop Backup Node
  3. IT职场人生系列之二十二:如何学习新语言(二)
  4. Quart 2D 绘制图形简单总结
  5. PowerPC VxWorks BSP分析7——image压缩
  6. RHCE课程-RH131Linux管理笔记八-安装和管理XEN虚拟机
  7. manjaro升级的一些问题
  8. “元宇宙”数字化理解
  9. linux apache 手动安装教程,linux下手动安装apache
  10. 远程usb端口映射_PLC远程控制