SSR 环境下路由配置与普通客户端路由配置差异
- 加载时机:
- 普通客户端路由:在浏览器端加载应用后,根据用户操作动态切换路由视图,路由逻辑完全在客户端运行。例如,用户点击链接,客户端JavaScript代码捕获点击事件,然后根据路由配置切换到相应组件。
- SSR 环境下路由:在服务器端就需要根据请求的URL确定要渲染的组件。服务器在接收到请求时,要根据路由配置找到对应的组件并将其渲染成HTML字符串返回给客户端。这意味着SSR路由配置需要在服务器启动时就加载并生效。
- 数据获取:
- 普通客户端路由:数据获取通常在客户端组件挂载后进行。比如,在组件的
onMount
生命周期函数中发起API请求获取数据。
- SSR 环境下路由:需要在服务器端提前获取数据并填充到组件中,以便生成包含完整数据的HTML。这样搜索引擎抓取时能获取到完整内容。
配置路由使搜索引擎正确抓取页面内容
- 使用合适的路由库:在Solid.js中,可以使用
solid - router
。在SSR环境下,首先要在服务器端和客户端都引入并配置该路由库。
import { renderToString } from '@solidjs/ssr';
import { createServer } from 'http';
import { RouterContext, matchPath } from'solid - router';
import App from './App';
const server = createServer((req, res) => {
const location = req.url;
const route = matchPath(location);
const context = { route };
const html = renderToString(() => (
<RouterContext.Provider value={context}>
<App />
</RouterContext.Provider>
));
res.writeHead(200, { 'Content - Type': 'text/html' });
res.end(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF - 8">
<meta name="viewport" content="width=device - width, initial - scale = 1.0">
<title>SSR Solid.js App</title>
</head>
<body>
<div id="root">${html}</div>
<script src="/client.js"></script>
</body>
</html>
`);
});
const port = 3000;
server.listen(port, () => {
console.log(`Server running on port ${port}`);
});
import { render } from'solid - dom';
import { RouterContext } from'solid - router';
import App from './App';
const root = document.getElementById('root');
render(() => (
<RouterContext.Provider value={{}}>
<App />
</RouterContext.Provider>
), root);
- 确保路由路径的可预测性:使用静态路由路径,避免使用动态参数过多且复杂的路由,因为搜索引擎可能难以理解复杂动态路径。例如,对于文章详情页,使用
/article/123 - article - title
比/article?id = 123
更利于SEO。
处理数据预取增强SEO效果
- 服务器端数据预取:在服务器端,根据路由匹配到的组件,在渲染组件前获取所需数据。例如,如果有一个文章列表页,在服务器端根据路由确定要渲染文章列表组件时,提前从数据库或API获取文章数据。
- 示例:假设文章数据获取函数为
fetchArticles
。
import { renderToString } from '@solidjs/ssr';
import { createServer } from 'http';
import { RouterContext, matchPath } from'solid - router';
import App from './App';
import { fetchArticles } from './api';
const server = createServer(async (req, res) => {
const location = req.url;
const route = matchPath(location);
let articles;
if (route.path === '/articles') {
articles = await fetchArticles();
}
const context = { route, articles };
const html = renderToString(() => (
<RouterContext.Provider value={context}>
<App />
</RouterContext.Provider>
));
res.writeHead(200, { 'Content - Type': 'text/html' });
res.end(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF - 8">
<meta name="viewport" content="width=device - width, initial - scale = 1.0">
<title>SSR Solid.js App</title>
</head>
<body>
<div id="root">${html}</div>
<script src="/client.js"></script>
</body>
</html>
`);
});
const port = 3000;
server.listen(port, () => {
console.log(`Server running on port ${port}`);
});
- 传递预取数据到客户端:在服务器端渲染时,将预取的数据通过上下文或其他方式传递给客户端,以便客户端在hydration(将服务器端渲染的静态HTML激活为动态应用)过程中使用,避免重复数据获取。例如,在上述代码中,将
articles
数据通过context
传递,客户端组件可以从context
中获取该数据。