mcpField
S
server-side-rendering

server-side-rendering

github.com/patternsdev开发257954 次安装28 周前更新
代码仓库

关于 server-side-rendering

面向 Web 开发者的服务端渲染指南,介绍服务器生成 HTML、常见收益与限制,以及 React 和 Next.js 的实现方式。适用于重视 SEO 和快速呈现内容的页面。

主要功能

  1. 01服务端生成页面 HTML
  2. 02减少客户端渲染所需 JavaScript
  3. 03支持 React 水合
  4. 04介绍 Next.js SSR 实现

适用场景

  1. 01为搜索引擎优化内容页面
  2. 02让内容密集页面更快显示
  3. 03在 React 页面中结合服务端渲染与客户端交互

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/patternsdev/skills --skill server-side-rendering

安装后在 Claude Code 中输入/server-side-rendering确认已加载。

详细介绍

服务端渲染

目录

服务端渲染(SSR)是最古老的网页内容渲染方式之一。SSR 会在响应用户请求时,生成页面内容的完整 HTML。内容可能包含来自数据存储或外部 API 的数据。

连接和获取数据的操作都在服务器上处理。用于格式化内容的 HTML 也由服务器生成。因此,使用 SSR 可以避免额外的数据获取和模板处理往返请求。这样一来,客户端不需要渲染代码,也无需向客户端发送对应的 JavaScript。

适用场景

  • 当 SEO 和快速的首次内容绘制(FCP)对应用很重要时,使用此方案
  • 适用于内容繁多、需要快速呈现给用户和搜索引擎的页面

不适用场景

  • 对于纯静态内容,静态渲染(SSG)已足够,并且可以避免按请求产生的服务器成本
  • 对于 SEO 无关紧要的内部仪表板或工具,CSR 架构更简单
  • 当每次请求的服务端渲染开销过高且无法进行缓存时

说明

  • 使用 Next.js 等提供内置 SSR 支持的框架
  • 考虑升级到 renderToPipeableStream(React 18+),以支持结合 Suspense 的流式 SSR
  • 将 SSR 与客户端水合结合,用于交互式页面
  • 注意 TTFB 的影响——优化服务器响应时间并考虑缓存
  • 探索将 React Server Components 作为 SSR 的补充,以减少客户端 JavaScript

详情

在 SSR 中,每个请求都会被单独处理,服务器会将其作为新请求进行处理。即使连续两个请求的输出没有太大区别,服务器仍会从头开始处理并生成内容。由于服务器由多个用户共用,因此在任意时刻,处理能力都由所有活跃用户共享。

经典 SSR 实现

下面通过一个简单示例,展示如何使用经典 SSR 和 JavaScript 在页面上显示并更新当前时间。

<!DOCTYPE html>
<html>
   <head>
       <title>Time</title>
   </head>
   <body>
       <div>
       <h1>Hello, world!</h1>
       <b>It is <div id=currentTime></div></b>
       </div>
   </body>
</html>
function tick() {
    var d = new Date();
    var n = d.toLocaleTimeString();
    document.getElementById("currentTime").innerHTML = n;
}
setInterval(tick, 1000);

请注意,这与生成相同输出的 CSR 代码有所不同。还要注意,虽然 HTML 是由服务器渲染的,但此处显示的时间是客户端本地时间,由 JavaScript 函数 tick() 填充。如果要显示其他与服务器相关的数据(例如服务器时间),则需要在 HTML 渲染之前将其嵌入其中。这意味着若不与服务器进行往返请求,这些数据就不会自动刷新。

优缺点

在服务器上执行渲染代码并减少 JavaScript,可带来以下优势。

JavaScript 更少,FCP 和 TTI 更快

当页面中有多个 UI 元素和应用逻辑时,与 CSR 相比,SSR 所需的 JavaScript 会少得多。因此,加载和处理脚本所需的时间也更短。FP、FCP 和 TTI 都会更短,且 FCP = TTI。使用 SSR 时,用户不必等待所有屏幕元素出现并变为可交互状态。

为客户端 JavaScript 腾出更多预算

开发团队需要遵守 JS 预算,以限制页面上的 JS 数量并达到预期性能。使用 SSR 时,由于页面渲染所需的 JS 被直接移除,因此可以为应用可能需要的第三方 JS 腾出更多空间。

支持 SEO

搜索引擎爬虫可以轻松抓取 SSR 应用的内容,从而提升页面的搜索引擎优化效果。

得益于上述优势,SSR 非常适合静态内容。不过,它也有一些缺点,因此并非适用于所有场景。

TTFB 较慢

由于所有处理都在服务器上进行,在以下一种或多种情况下,服务器的响应可能会延迟:

  • 多个用户同时访问,导致服务器负载过高。
  • 网络较慢。
  • 服务器代码未经过优化。
某些交互需要重新加载整个页面

由于客户端上没有全部代码,所有关键操作都需要频繁往返服务器,从而导致重新加载整个页面。这可能会延长交互间隔,因为用户需要等待更长时间才能进行下一步操作。因此,使用 SSR 无法实现单页应用。

使用 Next.js 实现 SSR

Next.js 框架也支持 SSR。它会在每次请求时于服务器上预渲染页面。可通过从页面导出一个名为 getServerSideProps() 的异步函数来实现,如下所示。

export async function getServerSideProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  };
}

context 对象包含 HTTP 请求和响应对象、路由参数、查询字符串、区域设置等键。

以下实现展示了如何使用 getServerSideProps(),以 React 格式在页面上渲染数据:

// data fetched from an external data source using `getServerSideProps`

const Users = ({ users, error }) => {
 return (
   <section>
     <header>
       <h1>List of users</h1>
     </header>
     {error && <div>There was an error.</div>}
     {!error && users && (
       <table>
         <thead>
           <tr>
             <th>Username</th>
             <th>Email</th>
             <th>Name</th>
           </tr>
         </thead>
         <tbody>
           {users.map((user, key) => (
             <tr key={key}>
               <td>{user.username}</td>
               <td>{user.email}</td>
               <td>{user.name}</td>
             </tr>
           ))}
         </tbody>
       </table>
     )}
   </section>
 );
};

export async function getServerSideProps() {
 try {
   // Fetch data from external API
   const res = await fetch("https://jsonplaceholder.typicode.com/users");
   const data = await res.json();

   // Pass data to the page via props
   return { props: { users: data, error: null } };
 } catch (error) {
   return { props: { users: null, error: true } };
 }
}

export default Users;
使用 React 实现服务器端渲染

React 可以进行同构渲染,这意味着它既能在浏览器中运行,也能在服务器等其他平台上运行。因此,可以使用 React 在服务器上渲染 UI 元素。

React 还可以与通用代码搭配使用,让同一份代码在多个环境中运行。这得益于在服务器上使用 Node.js。

ReactDOMServer.renderToString(element);

此函数会返回与 React 元素对应的 HTML 字符串。随后可将 HTML 渲染到客户端,以加快页面加载速度。

renderToString() 函数可以与 hydrateRoot() 搭配使用。这样既能保留在服务器上渲染的 HTML,也能在客户端上附加事件处理程序。

为实现这一点,我们会在客户端和服务器上为每个页面各使用一个 .js 文件。服务器上的 .js 文件负责渲染 HTML 内容,客户端上的 .js 文件负责对其进行水合。

服务器端代码:

app.get("/", (req, res) => {
  const app = ReactDOMServer.renderToString(<App />);
});

用于确保元素 App 完成水合的客户端代码:

import { hydrateRoot } from "react-dom/client";

hydrateRoot(document.getElementById("root"), <App />);

此处提供了一个完整的 React SSR 示例。

来源

评论

支持 Markdown