Reactjs Webpack 4和react loadable似乎无法为服务器端呈现创建正确的块

Reactjs Webpack 4和react loadable似乎无法为服务器端呈现创建正确的块,reactjs,webpack,lazy-loading,webpack-4,Reactjs,Webpack,Lazy Loading,Webpack 4,我正在尝试创建一个带有延迟加载导入的ssr react应用程序。 一切正常,除了它不能获取所有必需的块之外 我还想知道这是否与基于服务器响应的动态组件有关 Edit-它实际上渲染了所有需要的块,但当客户端接管并再次渲染时,它会抹去整个内容 因为它会重新渲染所有的内容,所以速度会慢很多 解析器发生在服务器端,当客户端接管时,它会获取更多信息 server.js const history = createHistory({ initialEntries: [urlPath], })

我正在尝试创建一个带有延迟加载导入的ssr react应用程序。 一切正常,除了它不能获取所有必需的块之外

我还想知道这是否与基于服务器响应的动态组件有关

Edit-它实际上渲染了所有需要的块,但当客户端接管并再次渲染时,它会抹去整个内容

因为它会重新渲染所有的内容,所以速度会慢很多

解析器发生在服务器端,当客户端接管时,它会获取更多信息 server.js

 const history = createHistory({
    initialEntries: [urlPath],
  })
  // const history = createHistory()
  const store = configureStore(history, {
    location: {
        ...
    },

  })

  const context = {}
  const htmlRoot = (
    <Provider store={store}>
      <StaticRouter location={urlPath} context={context}>
        <AppRoot />
      </StaticRouter>
    </Provider>
  )

  // pre fetching data from api
  store
    .runSaga(rootSaga)
    .done.then(() => {

        const RTS = renderToString(htmlRoot) + printDrainHydrateMarks()
        const head = Helmet.renderStatic() 
        console.log(printDrainHydrateMarks())

        res.status(code).send(renderDom(RTS, port, host, storeState, head))
      }
    })
    .catch(e => {
      console.log(e.message)
      res.status(500).send(e.message)
    })

  renderToString(htmlRoot)
  console.log(printDrainHydrateMarks())

  store.close()
} else {
  res.status(500).send(_err)
}
客户端

Loadable.preloadReady().then(() => {
    hydrate(
      <Provider store={store}>
        <ConnectedRouter history={history}>
          <AppRoot />
        </ConnectedRouter>
      </Provider>,
      domRoot,
    )
  })
欢迎提出任何意见或建议


有人建议尝试使用window.onload=()=>{但这种方法似乎也会变慢。

您应该使用ReactLoadablePlugin来创建可加载导入的列表:

new ReactLoadablePlugin({
  filename: './build/react-loadable.json',
})
使用“react loadable capture”,您可以找出渲染时需要哪些动态组件,并可以将它们的包添加到头文件中:

const content = ReactDOMServer.renderToString(
  <Loadable.Capture report={moduleName => modules.push(moduleName)}>
    <Provider store={configureStore()}>
      <StaticRouter location={req.url} context={context}>
        <App />
      </StaticRouter>

    </Provider>
  </Loadable.Capture>
);

  let bundles = getBundles(stats, modules);
  bundles.map((item) => {
      //add js to header
      })
此配置在WebpackV4中适用

您可以在此处找到使用React可加载服务器端渲染的完整文档:


我正在使用以路由为中心的代码拆分和。很抱歉,代码片段/伪代码太长,我已尽最大努力将其缩短。:)

首先构建一个阵列,用于映射相应的组件

let routeConfig = [
  {path: '/foo', component: 'Foo'},
  {path: '/bar', component: 'Bar'}
];
universal
函数确保可以在服务器端和客户端正确导入组件及其子组件。它足够智能,可以相应地延迟加载拆分的代码

import universal from 'react-universal-component';
const routes = routeConfig.map((item) =>{
  let route = {};
  route.path = item.path;
  route.component = universal(import(`./container/${item.component}`), options);
  return route;
});
在React组件中渲染路由器

class App extends React.Component {
 render() {
    return (
      <div>
        <Switch>
          {routes.map( route => <Route key={ route.path } { ...route } />)}
        </Switch>
      </div>
);}}
最后,
server.js
将用于代码拆分

const chunkNames = flushChunkNames();
const {js, styles, cssHash, scripts, stylesheets} = flushChunks(clientStats, {chunkNames});
res.send(`<!doctype html>
  <html>
    <head>
      ${styles}
    </head>
    <body>
      <div id="root">${app}</div>
      ${cssHash}
      ${js}
    </body>
  </html>`);
const chunkNames=flushChunkNames();
const{js,styles,cssHash,scripts,stylesheets}=flushChunks(clientStats,{chunkNames});
res.send(`
${style}
${app}
${cssHash}
${js}
`);

你应该考虑使用RealAtdiabrRead RADON,它比ReaCudioLoad提供的插件工作得更好。在我的例子中,它产生了巨大的差异!

< P>如果你使用TS加载程序尝试设置:

tsconfig.json

{
  .
  .
  .

  "module" : "esnext",
  "moduleResolution": "Node",
  .
  .
  .
}

问得好,但我还是不知道。
class App extends React.Component {
 render() {
    return (
      <div>
        <Switch>
          {routes.map( route => <Route key={ route.path } { ...route } />)}
        </Switch>
      </div>
);}}
  output: {
    filename: '[name].js',
    chunkFilename: '[name].js',
    path: path.resolve(__dirname, '../dist/client'),
    publicPath: '/xxxxxx/'
  },
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: '[name].css',
      chunkFilename: '[id].css'
  })],
  optimization: {
    splitChunks: {
      chunks: 'initial',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/, 
          name: 'vendor' // bundle all the npm module as vendor.js
}}}}
const chunkNames = flushChunkNames();
const {js, styles, cssHash, scripts, stylesheets} = flushChunks(clientStats, {chunkNames});
res.send(`<!doctype html>
  <html>
    <head>
      ${styles}
    </head>
    <body>
      <div id="root">${app}</div>
      ${cssHash}
      ${js}
    </body>
  </html>`);
{
  .
  .
  .

  "module" : "esnext",
  "moduleResolution": "Node",
  .
  .
  .
}