让我们更深入地了解服务器端渲染 (SSR) 的概念以及它如何增强 Web 应用程序的用户体验。
当用户访问您的网站时,他们通常最初会收到裸 HTML,然后触发加载其他资源,例如 JavaScript(例如 App.js)和 CSS(例如 style.css)。这种传统方法通常称为客户端渲染,意味着用户必须等待这些资源下载并执行才能看到任何有意义的内容。这种延迟可能会导致用户体验不佳,尤其是对于连接速度或设备较慢的用户而言。
服务器端渲染通过向用户发送完全渲染的 HTML 页面来响应其初始请求来解决此问题。此预渲染的 HTML 包含完整的标记,允许用户立即查看内容,而无需等待 JavaScript 加载和执行。
SSR 的主要优势包括:
减少最大内容绘制 (LCP) 的时间:用户可以更快地看到内容,因为服务器发送完整的 HTML 文档。
改进的 SEO:搜索引擎可以更有效地索引您的内容,因为内容可以轻松以 HTML 格式获取。
更好的初始用户体验:用户可以更快地开始阅读内容并与内容互动,从而提高参与率。
虽然 SSR 可以减少 LCP,但它可能会增加 与下一次绘制的交互 (INP) 的时间。这是页面加载后用户与页面交互所需的时间。目标是确保当用户决定与网站交互时(例如单击按钮),必要的 JavaScript 已在后台加载,从而使交互流畅且无缝。
SSR 的糟糕实现可能会导致用户看到内容但无法与其交互,因为 JavaScript 尚未加载。这可能比等待整个页面最初加载更令人沮丧。因此,持续监控和测量性能指标以确保 SSR 真正改善用户体验至关重要。
我们会将其分解为几个步骤:
我们首先创建一个 ClientApp.jsx 文件,它将处理所有特定于浏览器的功能。
// ClientApp.jsx import { hydrateRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import App from './App';
在这里,我们从react-dom/client 导入HydraRoot,从react-router-dom 导入BrowserRouter,以及我们的主要App 组件。
// ClientApp.jsx // Hydrate the root element with our app hydrateRoot(document.getElementById('root'), <BrowserRouter> <App /> </BrowserRouter> );
我们使用 HydroRoot 在客户端渲染我们的应用程序,指定根元素并使用 BrowserRouter 包装我们的应用程序。此设置可确保所有特定于浏览器的代码都保留在此处。
接下来,我们需要修改我们的App.jsx。
// App.jsx import React from 'react'; // Exporting the App component export default function App() { return ( <div> <h1>Welcome to My SSR React App!</h1> </div> ); }
在这里,为了演示目的,我们保持应用程序组件简单。我们将其导出,以便它可以在客户端和服务器环境中使用。
接下来,我们需要更新index.html以加载ClientApp.jsx而不是App.jsx,并添加解析令牌以拆分服务器中的HTML文件,以便我们可以流式传输根div中的内容。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="./vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite + React + TS</title> </head> <body> <div id="root"><!--not rendered--></div> <script type="module" src="./src/ClientApp.jsx"></script> </body> </html>
现在,让我们创建一个 ServerApp.jsx 文件来处理服务器端渲染逻辑。
// ServerApp.jsx import { renderToPipeableStream } from 'react-dom/server'; import { StaticRouter } from 'react-router-dom/server'; import App from './App'; // Export a function to render the app export default function render(url, opts) { // Create a stream for server-side rendering const stream = renderToPipeableStream( <StaticRouter location={url}> <App /> </StaticRouter>, opts ); return stream; }
我们需要更新 package.json 中的构建脚本来构建客户端和服务器包。
{ "scripts": { "build:client": "tsc vite build --outDir ../dist/client", "build:server": "tsc vite build --outDir ../dist/server --ssr ServerApp.jsx", "build": "npm run build:client && npm run build:server", "start": "node server.js" }, "type": "module" }
在这里,我们为客户端和服务器定义单独的构建脚本。 build:client 脚本构建客户端捆绑包,而 build:server 脚本使用 ServerApp.jsx 构建服务器捆绑包。构建脚本运行两个构建步骤,启动脚本使用 server.js(将在下一步中创建)运行服务器。
∴ 如果您不使用 TypeScript,请从客户端和服务器版本中删除 tsc。
最后,让我们在 server.js 中配置我们的 Node 服务器。
// server.js import express from 'express'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import renderApp from './dist/server/ServerApp.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const PORT = process.env.PORT || 3001; // Read the built HTML file const html = fs.readFileSync(path.resolve(__dirname, './dist/client/index.html')).toString(); const [head, tail] = html.split('<!--not rendered-->'); const app = express(); // Serve static assets app.use('/assets', express.static(path.resolve(__dirname, './dist/client/assets'))); // Handle all other routes with server-side rendering app.use((req, res) => { res.write(head); const stream = renderApp(req.url, { onShellReady() { stream.pipe(res); }, onShellError(err) { console.error(err); res.status(500).send('Internal Server Error'); }, onAllReady() { res.write(tail); res.end(); }, onError(err) { console.error(err); } }); }); app.listen(PORT, () => { console.log(`Listening on http://localhost:${PORT}`); });
In this file, we set up an Express server to handle static assets and server-side rendering. We read the built index.html file and split it into head and tail parts. When a request is made, we immediately send the head part, then pipe the stream from renderApp to the response, and finally send the tail part once the stream is complete.
By following these steps, we enable server-side rendering in our React application, providing a faster and more responsive user experience. The client receives a fully rendered page initially, and the JavaScript loads in the background, making the app interactive.
By implementing server-side rendering (SSR) in our React application, we can significantly improve the initial load time and provide a better user experience. The steps involved include creating separate components for client and server rendering, updating our build scripts, and configuring an Express server to handle SSR. This setup ensures that users receive a fully rendered HTML page on the first request, while JavaScript loads in the background, making the application interactive seamlessly. This approach not only enhances the perceived performance but also provides a robust foundation for building performant and scalable React applications.
以上是使用 Vite 和 React.js 进行服务器端渲染 (SSR) 指南的详细内容。更多信息请关注PHP中文网其他相关文章!