Webpack 4 и реагировать на загрузку не создают корректный фрагмент для отображения на стороне сервера

Я пытаюсь создать приложение ssr реагировать с ленивой загрузкой импорта. Все работает нормально, кроме того, что не получает все необходимые куски

Мне также интересно, если это связано с динамическим компонентом, который основан на ответе сервера

enter code here

Редактировать - на самом деле он рендерит все необходимые фрагменты, но стирает все целиком, когда клиентская часть берет верх и рендерит снова

Поскольку он перерисовывает все, он сильно замедляется.

enter image description here Синтаксический анализатор происходит на стороне сервера, и когда клиентская сторона берет на себя, он получает больше 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)
}

Prod Server

Loadable.preloadAll().then(() => {
  app.listen(PROD_PORT, (error) => {

  })
});

Клиентская сторона

Loadable.preloadReady().then(() => {
    hydrate(
      <Provider store={store}>
        <ConnectedRouter history={history}>
          <AppRoot />
        </ConnectedRouter>
      </Provider>,
      domRoot,
    )
  })

Настройка разделенных чанков

    styles: {
      name: 'styles',
      test: /\.css$/,
      chunks: 'all',
      enforce: true
    },

Любое мнение или совет приветствуется, пожалуйста,

Кто-то предложил попробовать с window.onload =() => {но этот подход тоже кажется замедленным.

Ответ 1

Вы должны использовать ReactLoadablePlugin, чтобы получить список загружаемых импортов:

new ReactLoadablePlugin({
  filename: './build/react-loadable.json',
})

Используя "реакцию на загрузку", вы можете узнать, какие динамические компоненты необходимы при рендеринге, и вы можете добавить их пакеты в ваш заголовочный файл:

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
      })

Это препятствует тому, чтобы реагирующая загружаемая часть стирала содержание и повторно представляла его.

Чтобы настроить Webpack для вывода правого чанка на основе динамически загружаемого компонента, сделайте следующее:

 optimization: {
    splitChunks: {
      cacheGroups: {
          default: false,
          vendors: false,
      }
  }
}

Эта конфигурация работает для меня в Webpack v4.

Вы можете найти полную документацию для работы с загружаемым рендерингом на стороне сервера здесь:

https://github.com/jamiebuilds/react-loadable

Ответ 2

Я использую ориентированное на маршрут расщепление кода с помощью реакционно-универсального компонента и промывочного патрона. Извините за длинный фрагмент кода/псевдо-код, я старался изо всех сил, чтобы сделать его короче. :)

Сначала создайте массив для реагирования маршрутизатора, отображающего соответствующие компоненты.

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 Component.

class App extends React.Component {
 render() {
    return (
      <div>
        <Switch>
          {routes.map( route => <Route key={ route.path } { ...route } />)}
        </Switch>
      </div>
);}}

Конфиг webpack определяет код разделения имен.

  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
}}}}

Наконец, server.js будет использовать flush chuck для разделения кода.

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>');

Ответ 3

Вы должны рассмотреть возможность использования ReactLoadableSSRAddon, он работает лучше, чем плагин, предоставляемый ReactLoadable . Для получения дополнительной информации см. эту ссылку. В моем случае это имело огромное значение!