【发布时间】:2019-07-16 12:52:22
【问题描述】:
我用 React、react-router、@loadable/component 创建了一个项目。
现在我正在尝试将 SSR 添加到该项目中。 我用 react-router 做了服务器端渲染。
然后我添加了@loadable/component 来导入所有页面组件:
import loadable from '@loadable/component';
const routersConfig = [
{
path: '/',
component: loadable(() => import('./Home')),
exact: true,
},
{
path: '/2',
component: loadable(() => import('./Home2')),
exact: true,
},
];
然后我添加了所有这部分代码:https://www.smooth-code.com/open-source/loadable-components/docs/server-side-rendering/
现在它可以工作了。 但它可以解决问题:加载时内容会闪烁。
我如何理解页面的加载过程:
- 浏览器获取 SSR 生成的内容(网络选项卡中的第一个查询)
- 浏览器呈现内容(带有左边距和上边距)
- 浏览器从 html(app.js、normalizer.js、vendor.js)下载两个入口点和供应商
- 浏览器执行 app.js 和 normalizer.js。左边距和上边距被删除。
- App.js 开始下载页面的块 - home.js。 此时内容消失
- home.js 下载后,内容又出现了。
我拍摄了一段视频来说明这个过程。 (对于质量,我很抱歉,stackoverflow 禁止大小超过 2MB 的文件)。我正在限制网络速度以想象所有页面的下载过程。
我的问题是为什么内容消失了?如何解决?
我的代码
server.js
const sheetStyledComponents = new ServerStyleSheet();
const sheetsJssRegistry = createSheetsRegistry();
const statsFile = path.resolve(process.cwd(), './build-ssr/dist/loadable-stats.json');
const extractor = new ChunkExtractor({
statsFile,
entrypoints: [
'app',
'normalize',
],
});
try {
const client = ApolloSSRClient();
const tree = (
<ApolloProvider client={client}>
<ApplyTheme sheetsRegistry={sheetsJssRegistry}>
<StaticRouter location={req.url}>
<Home />
</StaticRouter>
</ApplyTheme>
</ApolloProvider>
);
// there is combination of Apollo graphql, jss, styledComponent functions
const body = await getMarkupFromTree({
renderFunction: flow(
sheetStyledComponents.collectStyles.bind(sheetStyledComponents),
extractor.collectChunks.bind(extractor),
renderToString
),
tree,
});
const scriptTags = extractor.getScriptTags();
// It isn't used yet
const linkTags = extractor.getLinkTags();
const styleTags = sheetStyledComponents.getStyleTags();
const html = (await rawHtml)
.replace(
'</head>',
`
${styleTags}
<style type="text/css" id='jss-server-side-styles'>
${sheetsJssRegistry.toString()}
</style>
<script>
window.__APOLLO_STATE__ = ${JSON.stringify(client.extract())};
</script>
${scriptTags}
</head>
`
)
.replace('<div id="app"></div>', `<div id="app">${body}</div>`);
res.send(html);
index.jsx
const SSRApp = (
<ApolloProvider client={ApolloClient}>
<ApplyTheme>
<BrowserRouter>
<App />
</BrowserRouter>
</ApplyTheme>
</ApolloProvider>
);
loadableReady(() => (
ReactDOM.hydrate(
SSRApp,
document.getElementById('app'),
)
));
【问题讨论】:
-
我们能看到你的
组件以及你使用 ReactDOM 的代码吗?我认为这可能会有所帮助。 -
据我所知,您的 js 代码获取了
<div id="app">中的所有内容并从头开始渲染。从理论上讲,您的 js 不应该这样做,它应该连接到<div id="app">中的现有组件 -
在阅读了 react-router 的 github repo 上的文档之后,我们真的需要看看你的 Router 是在哪里定义的,以及它是如何定义的。
-
我相信您的整个网页都在闪烁,因为整个页面都包含在
中,当您导航到另一个页面时,它会更改内容。如果您希望标题不闪烁,则需要将标题移到 组件之外。试试看,让我知道结果。我对你的设置很感兴趣。 -
@JoshuaBlevins 我发现了错误。它只是试图渲染
SSR 而不是 。你可以在我的代码中看到它。
标签: javascript reactjs webpack server-side-rendering react-loadable