带有样式组件的 SSR - 当 app.js 加载网站时缺少一些样式
SSR with styled-components - when app.js loads site missing few styles
我用 styled-components
实现了 SSR。
当使用 SSR 加载页面时,一切看起来都很好。但是,当app.js
与SSR版本一起加载和水合时,页面缺少一些样式并且很少有元素中断。
更重要的是 - 当我在本地打开应用程序时,使用 npm start
或基本上只是删除我的 SSR,一切正常并且样式被正确应用。
重要提示:当我进入页面并且 app.js
负载和样式被破坏时,如果我更改路线 - 新路线正确应用样式和问题离开了。
- SSR 负载 - 样式很好
- 然后在几秒钟后 app.js 负载(水合过程)- 样式损坏
运行 本地应用程序 - 样式没问题
运行 没有 SSR 的应用程序 - 样式没问题
所以简而言之 - 如果我使用 SSR,我会缺少一些样式,SSR 本身 returns 正确的样式,但在 app.js
水合作用后,很少有组件损坏。
我打赌这可能是 styled-components
的问题。 SSR 工作正常,其他一切都很好,除了一个缺少样式的组件。
我知道这是关于我的案例的相当不完整的信息,但是为了显示可能导致此错误的每个部分,我应该发布整个项目,但是也许您遇到过类似的案例并且您会以某种方式帮助我。谢谢。
编辑:我的babel-styled-component-plugin
配置:
['babel-plugin-styled-components', {
ssr: true,
displayName: false,
fileName: false,
transpileTemplateLiterals: false,
minify: false,
}],
两件事...
1) 确保您使用的是 babel plugin;没有它,无法保证生成的 class 名称在服务器和客户端之间是相同的。
2) 在您的捆绑设置中,确保您对客户端和服务器使用的 babel 配置基本相同。如果存在重大差异并且文件以非常不同的方式转换,则可能会影响生成的 class 名称输出。
我分4步解决了
Server.js
app.get('*', handleRender);
function handleRender (req, res) {
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {};
const promise = activeRoute.fetchInitialData ?
activeRoute.fetchInitialData(req.path) :
Promise.resolve();
promise.then((data) => {
const context = { data };
const store = configureStore({});
const sheet = new ServerStyleSheet(); // ==== STEP -1
const preloadedState = store.getState();
const html = renderToString(
sheet.collectStyles( // === STEP --2
<Provider store={store}>
<StaticRouter location={req.url} context={context}>
<App/>
</StaticRouter>
</Provider>
)
);
const styles = sheet.getStyleTags(); /// === STEP 3
res.send(renderFullPage(html, styles, preloadedState));
});
function renderFullPage (html, styles, preloadedState) {
return `
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>body,html,div,ul,p{margin:0;padding:0;}</style>
<title>Characters of Rick And Morty Show</title>
<style>
${globalStyles}
</style>
${styles} // === STEP 4
</head>
<body>
<div id="root">${html}</div>
<script>
// WARNING: See the following for security issues around embedding JSON in HTML:
// https://redux.js.org/recipes/server-rendering/#security-considerations
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
/</g,
'\u003c'
)}
</script>
<script src="client_bundle.js"></script>
</body>
</html>
`;
}
客户
hydrate(<BrowserRouter>
<Provider store={store}>
<App/>
</Provider>
</BrowserRouter>, document.getElementById('root'));
我用 styled-components
实现了 SSR。
当使用 SSR 加载页面时,一切看起来都很好。但是,当app.js
与SSR版本一起加载和水合时,页面缺少一些样式并且很少有元素中断。
更重要的是 - 当我在本地打开应用程序时,使用 npm start
或基本上只是删除我的 SSR,一切正常并且样式被正确应用。
重要提示:当我进入页面并且 app.js
负载和样式被破坏时,如果我更改路线 - 新路线正确应用样式和问题离开了。
- SSR 负载 - 样式很好
- 然后在几秒钟后 app.js 负载(水合过程)- 样式损坏
运行 本地应用程序 - 样式没问题
运行 没有 SSR 的应用程序 - 样式没问题
所以简而言之 - 如果我使用 SSR,我会缺少一些样式,SSR 本身 returns 正确的样式,但在 app.js
水合作用后,很少有组件损坏。
我打赌这可能是 styled-components
的问题。 SSR 工作正常,其他一切都很好,除了一个缺少样式的组件。
我知道这是关于我的案例的相当不完整的信息,但是为了显示可能导致此错误的每个部分,我应该发布整个项目,但是也许您遇到过类似的案例并且您会以某种方式帮助我。谢谢。
编辑:我的babel-styled-component-plugin
配置:
['babel-plugin-styled-components', {
ssr: true,
displayName: false,
fileName: false,
transpileTemplateLiterals: false,
minify: false,
}],
两件事...
1) 确保您使用的是 babel plugin;没有它,无法保证生成的 class 名称在服务器和客户端之间是相同的。
2) 在您的捆绑设置中,确保您对客户端和服务器使用的 babel 配置基本相同。如果存在重大差异并且文件以非常不同的方式转换,则可能会影响生成的 class 名称输出。
我分4步解决了
Server.js
app.get('*', handleRender);
function handleRender (req, res) {
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {};
const promise = activeRoute.fetchInitialData ?
activeRoute.fetchInitialData(req.path) :
Promise.resolve();
promise.then((data) => {
const context = { data };
const store = configureStore({});
const sheet = new ServerStyleSheet(); // ==== STEP -1
const preloadedState = store.getState();
const html = renderToString(
sheet.collectStyles( // === STEP --2
<Provider store={store}>
<StaticRouter location={req.url} context={context}>
<App/>
</StaticRouter>
</Provider>
)
);
const styles = sheet.getStyleTags(); /// === STEP 3
res.send(renderFullPage(html, styles, preloadedState));
});
function renderFullPage (html, styles, preloadedState) {
return `
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>body,html,div,ul,p{margin:0;padding:0;}</style>
<title>Characters of Rick And Morty Show</title>
<style>
${globalStyles}
</style>
${styles} // === STEP 4
</head>
<body>
<div id="root">${html}</div>
<script>
// WARNING: See the following for security issues around embedding JSON in HTML:
// https://redux.js.org/recipes/server-rendering/#security-considerations
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
/</g,
'\u003c'
)}
</script>
<script src="client_bundle.js"></script>
</body>
</html>
`;
}
客户
hydrate(<BrowserRouter>
<Provider store={store}>
<App/>
</Provider>
</BrowserRouter>, document.getElementById('root'));