簡體   English   中英

用 SSR 反應 HMR

[英]React HMR with SSR

我正在嘗試為 React 應用程序設置 SSR,當我第一次在development環境中啟動服務器時一切正常(服務器發送瀏覽器 HTML 和 CSS),在更改我的應用程序的源代碼后,出現錯誤:

在此處輸入圖片說明

拋出這個錯誤是因為服務器上的源代碼已經過時,但是客戶端有一個新版本並且 React 通知我這個問題。 我認為解決這個問題的方法是一種稱為 HMR(熱模塊更換)的機制,但是設置它對我來說很困難。

我的服務器 Webpack-config 如下所示:

const serverConfig = merge(commonConfig, {
  name: 'server',
  target: 'node',
  externals: [
    nodeExternals({
      whitelist: ['webpack/hot/poll?1000'],
    }),
  ],
  entry: ['webpack/hot/poll?1000', appServerEntry],
  output: {
    path: path.resolve(appDist, 'server'),
    filename: 'index.js',
  },
  plugins: [new webpack.HotModuleReplacementPlugin()],
  resolve: {
    extensions: ['.js', '.jsx', '.json'],
  },
});

在每個請求服務器上呈現一個新版本的 UI

app.get('*', (request, response) => {
  const staticAssets = getStaticAssets();
  const routerContext = {};
  const renderStream = renderDocumentToStream({
    staticAssets,
    request,
    routerContext,
  });
  const cacheStream = createCacheStream(request.path);

  response.writeHead(200, { 'Content-Type': 'text/html' });
  response.write('<!DOCTYPE html>');

  cacheStream.pipe(response);
  renderStream.pipe(cacheStream);
});

對於熱重載,我使用webpackDevMiddlewarewebpackHotMiddleware

const webpackInstance = webpack(webpackConfig);
const clientCompiler = webpackInstance.compilers.find(cmpl => cmpl.name === 'client');

app.use(
  webpackDevMiddleware(clientCompiler, {
    hot: true,
    stats: 'errors-only',
  }),
);
app.use(webpackHotMiddleware(clientCompiler));

用於將App渲染到NodeStream renderDocumentToStream函數:

import App from './App';

renderDocumentToStream: ({ request, staticAssets, routerContext }) => {
  const rootMarkup = renderToString(
    <StaticRouter location={request.url} context={routerContext}>
      <App />
    </StaticRouter>
  );

  return renderToNodeStream(
    <Document
      rootMarkup={rootMarkup}
      staticAssets={staticAssets}
    />,
  );
},

if (module.hot) {
  console.log('HERE-0');
  module.hot.accept('./App', () => {
    console.log('HERE-1');
  });
}

當服務器在stdout啟動時記錄了console.log第一次調用

在此處輸入圖片說明

即使App.jsx已更改,第二次調用console.log未記錄

在此處輸入圖片說明

我做錯了什么?

警告清楚地表明客戶端與服務器的內容不同。 這不是一個錯誤,而是一個警告,這意味着,會有性能影響,因為React必須在客戶端重新渲染,因此SSR的整個目的將被打敗。 請檢查並確保客戶端也獲得與服務器相同的水合作用。 這應該解決問題。

我不認為有可能解決,因為服務器端不會刷新HMR的更改。

個人在使用SSR進行React時我設置nodemon來監聽SSR輸出文件上的文件更改並重新啟動應用程序。 不幸的是,這並不像HMR那么快,你失去了當前的狀態,但我不認為如果你將使用SSR(或忽略警告)有另一種選擇

使用Next.js時也是如此: https//github.com/zeit/next.js/issues/791

這似乎解決了我的react-ssr-kit的 HMR更新期間的客戶端和服務器不匹配問題:

 const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate;

我的設置略有不同,但它仍然適用於您的:

import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";
import App from "root";
import routes from "routes";
import configureStore from "store/configureStore";

const history = createBrowserHistory(); // create browserhistory
const initialState = window.__INITIAL_PROPS__; // grabs redux state from server on load
const store = configureStore(history, initialState); // sets up redux store with history and initial state

const renderApp = props => {
  const renderMethod = module.hot ? ReactDOM.render : ReactDOM.hydrate; // if module is hot, use ReactDOM's render, else hydrate

  renderMethod(<App {...props} />, document.getElementById("root"));
};

renderApp({ routes, history, store }); // initial App render (ReactDOM.hydrate)

// enable webpack hot module replacement
if (module.hot) {
  module.hot.accept("./routes", () => {
    try {
      const nextRoutes = require("./routes").default;
      renderApp({ routes: nextRoutes, history, store }); // hot-module updates (ReactDOM.render)
    } catch (err) {
      console.error(`Routes hot reloading error: ${err}`);
    }
  });
}

此警告可能意味着您有一個組件需要在客戶端以不同方式呈現,並且您沒有確保“第一遍”呈現在服務器端和客戶端是相同的。

它們可以不同,例如,如果您在沒有數據時加載微調器,並且這些數據不會在服務器端存在,那么繼續並確保微調器始終在服務器上呈現瀏覽器上的“第一遍”渲染(在 componentDidMount() 被觸發之前的渲染調用)是相同的。

然后,當您的數據存在時,觸發狀態更改為“2nd-pass”渲染。

另外,我警告的一件事是使用module.hot ? ReactDOM.render : ReactDOM.hydrate module.hot ? ReactDOM.render : ReactDOM.hydrate . module.hot ? ReactDOM.render : ReactDOM.hydrate

我后悔在工作中使用這種方法,因為它掩蓋了在開發中難以檢測的不匹配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM