Webpack 4 и реагировать на загрузку не создают корректный фрагмент для отображения на стороне сервера
Я пытаюсь создать приложение ssr реагировать с ленивой загрузкой импорта.
Все работает нормально, кроме того, что не получает все необходимые куски
Мне также интересно, если это связано с динамическим компонентом, который основан на ответе сервера
enter code 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 . Для получения дополнительной информации см. эту ссылку. В моем случае это имело огромное значение!