react服務器渲染下,hot reload解決方案

原文連接javascript

前言

react客戶端渲染的前端界面配合webpack-dev-server, react-hot-loader很容易實現前端開發過程當中的局部刷新。然而配合node服務器的react-isomorphic實現局部刷新,同時更新client, server端的代碼並不是易事。
以下介紹一種可行的實施方案:github

適用於 koa2, react-hot-loader3, react-router無關緊要。web

Demo代碼地址:https://github.com/lanjingling0510/blog/tree/master/react-isomorphic-hot-exampleexpress

hot reload分析

image

react靜態資源熱加載分析

react靜態資源的熱加載配置並不複雜。webpack-dev-server負責從新編譯代碼,react-hot-loader負責熱加載。

Note:webpack-dev-server也能夠用開一個express服務器配合webpack-dev-middlewarewebpack-hot-middleware中間件實現

  1. 配置webpack.client-dev.js:

plugins: [
    new webpack.HotModuleReplacementPlugin()
]

// ...

entry: [
    'react-hot-loader/patch',
    'webpack-dev-server/client?http://127.0.0.1:8080',
    'webpack/hot/only-dev-server',
    './src/client/home', // 入口路徑
]
  1. 修改babel配置文件

"plugins": [
    "react-hot-loader/babel"
]
  1. 修改入口文件

import React from 'react';
import ReactDOM from 'react-dom';

// 共享的組件頁面
import Home from '../shared/page/Home';
// 熱加載組件
import ReactHotLoader from '../shared/component/ReactHotLoader';
const container = document.getElementById('react-container');

function renderApp(TheApp) {
    ReactDOM.render(
      <ReactHotLoader>
          <TheApp />
      </ReactHotLoader>,
      container
    );
}

renderApp(Home);

// 下面的代碼用來支持咱們熱加載應用
if (__DEV__ && module.hot) {
    // 接受這個文件的修改用來熱加載
    module.hot.accept('./home.js');
    // 應用任何的改變將形成熱加載,從新渲染。
    module.hot.accept(
      '../shared/page/Home',
      () => renderApp(require('../shared/page/Home').default)
    );
}

react服務器配置分析

開發模式下,server端的配置比較複雜,須要考慮的事情以下:

  • 監聽server代碼的變更。

  • 須要從新編譯server代碼

  • 從新開啓server服務器,並保證require最新的server代碼

  • 保證server端口按需開關,不衝突

  1. 監聽server代碼

// 監聽server文件的變化,若是被修改則調用compileHotServer
 const watcher = chokidar.watch([
     path.resolve(__dirname, '../src'),
     path.resolve(__dirname),
 ], {ignored: path.resolve(__dirname, '../src/client')});

 watcher.on('ready', () => {
     watcher
     .on('add', compileHotServer)
     .on('addDir', compileHotServer)
     .on('change', compileHotServer)
     .on('unlink', compileHotServer)
     .on('unlinkDir', compileHotServer);
 });
  1. 關閉全部與客戶端的鏈接,關閉server服務器,從新編譯server代碼

// 關閉全部鏈接,關閉服務器,從新編譯
 function compileHotServer() {
     compiling ++;
     // listenerManager實例包含當前web服務器對象和客戶端鏈接的socket集合
     if (listenerManager) {
         listenerManager.dispose(true).then(runCompiler);
     } else {
         runCompiler();
     }
 }
 
 // webpack從新編譯
 function runCompiler() {
    compiler.run(() => undefined);
 }
  1. 從新開啓server服務器

// server代碼編譯完成
 // 開啓server服務器
 compiler.plugin('done', stats => {
     compiling --;
     if (compiling !== 0) return;

     if (stats.hasErrors()) {
         console.log(stats.toString());
         return;
     }

     console.log('? ?  Build server bundle done.');
     // 確保新的server bundles 代碼不在module cache當中
     Object.keys(require.cache).forEach((modulePath) => {
         if (modulePath.indexOf(compiler.options.output.path) !== -1) {
             delete require.cache[modulePath];
         }
     });

     try {
         const listener = require(compiledOutputPath).default;
         listenerManager = new ListenerManager(listener, 'server');
     } catch (err) {
         console.log(err);
     }
 });

待解決

. react-router包含的頁面組件更新後,提示[react-router] You cannot change <Router routes>; it will be ignored,但不影響刷新

總結

經過以上配置,能夠實現修改代碼後,實現server和client代碼的更新以及hot reload。
代碼開發過程當中,須要開啓兩個端口,分別用來提供client端靜態資源的編譯和後臺的server。

若是在開發模式下,有更完善的react isomoriphic服務器渲染熱加載的解決方案,歡迎你們積極貢獻 ?

相關文章
相關標籤/搜索