用 SSR 反应 HMR

Pav*_*vel 6 javascript node.js reactjs webpack

我正在尝试为 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'],
  },
});
Run Code Online (Sandbox Code Playgroud)

在每个请求服务器上呈现一个新版本的 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);
});
Run Code Online (Sandbox Code Playgroud)

对于我使用的热重载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));
Run Code Online (Sandbox Code Playgroud)

renderDocumentToStream功能用于渲染AppNodeStream

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');
  });
}
Run Code Online (Sandbox Code Playgroud)

当服务器在stdout记录的第一次调用中启动时console.log

在此处输入图片说明

console.log未记录的第二次调用,即使App.jsx已更改

在此处输入图片说明

我做错了什么?

小智 1

该警告清楚地表明客户端和服务器的内容不同。这不是一个错误,而是一个警告,这意味着将会对性能产生影响,因为 React 必须在客户端重新渲染,因此 SSR 的整个目的将落空。请检查并确保客户端也获得与服务器相同的水合作用。这应该可以解决问题。