react课程24-SSR概念引入及手写

Last updated on September 30, 2024 pm

本小节介绍SSR和CSR的区别、一些浏览器性能标准以及如何手写SSR

一、CSR、SSR、SEO、LCP、FCP、CDN

(1)比较CSR和SSR图片版

image-20240929231551242

image-20240929231516523

image-20240929231606502

(2)CSR

1、定义

在客户端渲染中,网页的 HTML、CSS 和 JavaScript 由浏览器处理,所有的渲染工作在客户端进行。

2、工作原理
  1. 用户访问网页,服务器返回一个空的 HTML 框架以及 JavaScript 和 CSS 文件。
  2. 浏览器下载并执行 JavaScript,动态生成并渲染网页内容。
3、优点
  • 快速的交互:页面内容加载后,用户的操作无需再次请求服务器,响应速度快。
  • 减少服务器负担:服务器只需要提供静态文件,减轻了负担。
  • 丰富的用户体验:可以实现更复杂的交互和动画效果,适合单页应用(SPA)。
4、缺点
  • 首次加载时间长:由于需要下载和解析 JavaScript,首次内容绘制(FCP)可能较慢。
  • SEO 劣势:搜索引擎爬虫可能无法完全理解动态生成的内容,影响 SEO。

(3)SSR

1、定义

在服务器端渲染中,网页的 HTML 在服务器上生成,然后发送到客户端。

2、工作原理
  1. 用户访问网页,服务器处理请求并生成完整的 HTML。
  2. 服务器返回生成的 HTML 内容,浏览器直接渲染这个内容。
3、优点
  • 快速的首次加载:由于服务器返回完整的 HTML,用户能够更快地看到页面内容。
  • SEO 友好:搜索引擎能够直接抓取服务器返回的 HTML,有助于提升搜索排名。
4、缺点
  • 服务器负担重:服务器需要为每个请求生成 HTML,可能导致性能瓶颈。
  • 交互响应较慢:用户操作需要发送请求到服务器并等待响应,可能影响交互体验。

(4)SEO

SEO(Search Engine Optimization,搜索引擎优化)是一种通过优化网站和内容,提高其在搜索引擎结果页面(SERP)中排名的技术和策略。其目标是增加网站的可见性,从而吸引更多的自然流量。

1、主要组成部分
  • 关键词研究:确定目标受众使用的关键词和短语,以便在内容中合理嵌入这些关键词。
  • 页面优化:包括优化标题标签、元描述、URL 结构、图像替代文本等,以确保搜索引擎能够理解页面内容。
  • 内容优化:创建高质量、有价值且相关的内容,以满足用户需求并鼓励他们停留在页面上。
  • 技术SEO:包括提高网站加载速度、确保移动友好性、优化网站结构和内部链接等,使搜索引擎能够更好地抓取和索引网站。
  • 外部链接建设:通过获取其他网站的链接,提升网站的权威性和可信度,增强搜索引擎对该网站的信任度。
  • 用户体验(UX):提高网站的可用性和用户体验,确保访问者能够顺利浏览和找到所需信息。
2、重要性:
  • 提高可见性:优化后的网站在搜索引擎中排名更高,能吸引更多的访问者。
  • 增加流量:自然流量通常比付费广告更具成本效益,长远来看更可持续。
  • 建立品牌信任:高排名的网站通常被视为可信赖的来源,有助于建立品牌的信誉。
  • 提高转化率:优化后的内容更符合用户需求,有助于提高潜在客户的转化率。

(5)LCP

LCP(Largest Contentful Paint,最大内容绘制)是网页性能评估中的一个重要指标,用于衡量用户在页面加载过程中感知到的主要内容何时渲染完成。它是 Google 的 Web Vitals 指标之一,旨在帮助开发者改善用户体验。

1、定义

LCP 测量的是从页面开始加载到页面上最大的可见内容元素(如图像、视频、块级文本等)完全绘制的时间。这个时间越短,用户体验通常越好。

2、重要性
  • 用户体验:LCP 反映了用户在访问网页时的等待时间。较长的 LCP 可能意味着用户在加载内容时的挫败感,从而影响整体的用户体验。
  • 搜索引擎优化(SEO):Google 已将 LCP 作为网页性能的一个重要排名因素,优化 LCP 有助于提升网站在搜索引擎结果中的排名。
3、如何改善

优化图像和视频:确保使用适当格式和压缩的图像,减少文件大小,提高加载速度。

使用CDN:通过 CDN 加速内容交付,减少从服务器到用户的延迟。

减小CSS和JS的体积:精简和压缩资源,减少加载时间,确保主要内容能够尽快渲染。

优先加载关键资源:使用 link rel="preload" 标签提前加载重要资源,确保用户快速看到页面内容。

使用SSR:通过 SSR 提高初始加载速度,使得内容更快地可见。

(6)FCP

FCP(First Contentful Paint,首次内容绘制)是网页性能评估中的一个重要指标,旨在衡量用户首次看到任何可见内容(如文本、图像等)所需的时间。它是 Google 的 Web Vitals 指标之一,用于评估网页加载的速度和用户体验。

1、定义

FCP 测量的是从页面开始加载到浏览器绘制出任何可见内容的时间。这包括页面的文本、图像、SVG 图形等。

2、重要性
  • 用户体验:FCP 是用户感知加载性能的第一个重要信号。较快的 FCP 表示用户能够更早地看到内容,从而提升用户体验。
  • SEO:同上
3、如何改善
  • 优化资源加载:确保使用合适的图像格式和压缩,减少文件大小,加快加载速度。
  • 使用优先级加载:通过将关键 CSS 和 JavaScript 放在 <head> 中,确保它们优先加载。
  • 避免阻塞渲染:减少外部 CSS 和 JavaScript 文件的数量,避免阻塞初始渲染。
  • 利用服务器端渲染(SSR):提高初始加载速度,使内容更早呈现给用户。
  • 使用 CDN(内容分发网络):通过 CDN 加速资源的交付,减少从服务器到用户的延迟。

(7)CDN

(Content Delivery Network,内容分发网络)是一种分布式的网络架构,旨在提高网站内容的加载速度和可用性。CDN 通过在全球多个位置部署缓存服务器,来将内容更接近用户,从而优化数据传输。

1、工作原理
  • 内容缓存:CDN 在其边缘服务器上缓存静态资源(如图像、CSS、JavaScript 文件等),这些资源会在用户访问时快速提供。
  • 智能路由:当用户请求某个资源时,CDN 会根据用户的地理位置和当前网络状况,选择离用户最近的边缘服务器来响应请求。
  • 动态内容处理:对于动态内容,CDN 可以通过负载均衡和智能路由等技术来优化数据传输,提高响应速度。
2、优点
  • 提高加载速度:通过将内容分发到离用户更近的服务器,减少延迟,提升加载速度。
  • 减轻服务器负担:将大量的静态资源请求转发给 CDN,减轻源服务器的压力。
  • 提高可用性和可靠性:如果某个边缘服务器出现故障,CDN 可以自动将请求转发到其他可用的服务器,提高网站的可靠性。
  • 增强安全性:CDN 可以提供 DDoS 保护、SSL 加密等安全功能,帮助网站抵御攻击。
3、常见的服务提供商

Cloudflare、Akamai、Amazon CloudFront、Google Cloud CDN、Fastly

二、Manual SSR with React DOM +Node.js

(1)起步

🐈‍⬛新建文件:server.js -> npm init初始化工程(一直Enter就好了) -> 出现package.json

npm --watch server.js 添加watch关键字,否则每次修改都须重新运行


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const { createServer } = require('http');
const { parse } = require('url');

const server = createServer((req, res) => {
const pathName = parse(req.url, true).pathname;

if (pathName === '/') {
res.end('Hello World');
} else if (pathName === '/test') {
res.end('TEST');
} else {
res.end('URL not found');
}
});
//监听端口
server.listen(8000, () => console.log('listening for requests on port 8000'));
1、引入模块

require('http'):导入 Node.js 的 http 模块,它提供了用于创建 HTTP 服务器的功能。createServer 是其中的一个方法,用于创建 HTTP 服务器。

require('url'):导入 url 模块,其中的 parse 方法用于解析请求的 URL,提取路径和查询参数等信息。

2、创建服务器

createServer():这是创建 HTTP 服务器的函数。它接收一个回调函数,回调函数中的 req 代表客户端的请求,res 代表服务器的响应。

parse(req.url, true):使用 url.parse() 方法解析客户端请求的 URL。第二个参数 true 表示将查询字符串转换为对象形式。req.url是客户端请求的 URL

pathname:表示请求的路径部分(不包含查询参数),例如 /test/

3、路由处理

res.end():该方法结束响应并发送数据到客户端。比如,res.end('Hello World') 就是将 “Hello World” 发送给客户端,并结束响应。

(2)返回HTML作为响应

1、读取HTML文件
1
const htmlTemplate = readFileSync(`${__dirname}/index.html`, 'utf-8');

readFileSync():这是 Node.js 内置的 fs(文件系统)模块中的同步方法,用于读取文件的内容

${__dirname}/index.html__dirname 是一个全局变量,表示当前文件所在的目录路径。${__dirname}/index.html 拼接得到完整的 index.html 文件路径。

'utf-8':这是文件读取的编码方式,确保文件内容被读取为字符串(HTML 文本内容)

htmlTemplate:保存了 index.html 文件的内容作为字符串,之后会在服务器响应时将其返回给客户端

2、服务器逻辑
1
2
res.writeHead(200, { 'Contnt-type': 'text/html' });
res.end(htmlTemplate);

res.writeHead(200):设置响应状态码为 200,表示请求成功。

{ 'Contnt-type': 'text.html' }:设置响应头的 Content-Type

(3)在server端运行jsx代码

npm i -D @babel/core @babel/preset-env @babel/preset-react @babel/register

npm i react react-dom


1、start.js启动文件

node --watch start.js 命令来运行start.js 而不是运行server.js

1
2
//加入日志验证是否正常执行了代码
console.log('Babel register is running...');

require('@babel/register')({ extensions: ['.js', '.jsx'] });

这行代码的作用是加载并启用 @babel/register,它可以在运行时动态地编译 JavaScript 和 JSX 文件。具体来说:

  • @babel/register 是 Babel 提供的一个运行时工具,它可以在代码执行时实时编译那些使用了现代 JavaScript 或 JSX 语法的文件。
  • extensions: ['.js', '.jsx'] 表示 Babel 应该处理 .js.jsx 文件。这样的话,在你运行这些文件时,它们会自动通过 Babel 转换为普通的 ES5 JavaScript(兼容 Node.js)。

require('./server.js');

这行代码的作用是加载并运行 server.js 文件。

  • require('./server.js') 是 Node.js 中的模块加载方式,用来加载当前目录下的 server.js 文件。
  • 由于第一行代码已经启用了 @babel/registerserver.js 文件中的现代 JavaScript 语法(如 ES6 和 JSX)会被 Babel 实时编译并执行。
2、server.js
1
2
const { renderToString } = require('react-dom/server');
const React = require('react');

react-dom/server:用于将 React 组件渲染为字符串的模块,适用于服务器端渲染

react:React 库,用于创建组件。

1
2
const renderedReact = renderToString(<Home />);
const html = htmlTemplate.replace('%%%Content%%%', renderedReact);

使用 renderToString(<Home />)Home 组件渲染为 HTML 字符串。

将渲染结果插入到 HTML 模板中,替换 %%%Content%%% 占位符。

(如果不插入HTML中会产生渲染问题、交互问题等)

(4)Hydrate

hydrate在前端开发中通常指的是一个过程,特别是在使用框架如 React、Vue 和 Svelte 时,将服务器渲染的 HTML 结构与客户端的 JavaScript 代码结合起来,以便实现动态交互,并解决静态内容与动态内容之间的不一致问题。(在服务器上渲染HTML意味着从React应用程序中删除所有的交互性?!)

1、将静态内容转化为动态组件
  • 静态HTML:当服务器端渲染 React 组件时,生成的 HTML 是静态的,没有任何事件处理或状态管理。
  • hydrate 的作用:调用 ReactDOM.hydrate() 函数可以将已有的静态 HTML 转换为 React 组件,使其具备动态交互能力。React 会重新绑定事件处理器,初始化组件的状态,并使组件的生命周期方法正常工作
2、减少重新渲染
  • 减少不必要的重新渲染:通过使用 hydrate,React 可以利用已有的静态 HTML,而不是从头开始渲染组件。这意味着在初始加载时,不需要重新生成 HTML,从而提高了性能。(只有HTML的DOM树和Bundle的DOM树相等时,才会渲染)
  • 状态保留:hydrate 使得在客户端的状态可以与服务器端渲染时的状态保持一致,避免了状态丢失的问题。
3、保持交互性
  • 事件处理:通过 hydrate,React 将自动为已渲染的 HTML 元素绑定事件处理器。例如,按钮的点击事件、输入框的变化事件等,这些在 SSR 时是无法直接处理的。
  • 组件更新:当用户与组件交互时,hydrate 使得组件可以根据状态变化进行更新,而不需要重新渲染整个组件树。
4、确保一致性
  • 避免内容闪烁:在客户端渲染时,hydrate 确保服务器渲染的内容与客户端渲染的内容保持一致,避免了闪烁和内容不一致的问题。
  • 快速响应:用户在客户端与页面交互时,可以立即感知到变化,因为 hydrate 确保了用户交互的流畅性和及时响应。
5、优点

通过 hydrate,React 能够有效地将服务器端生成的静态内容转化为具有交互性的动态组件,确保页面在用户交互时的流畅性和一致性。这一过程避免了重新渲染带来的性能损失,同时为用户提供了更好的体验

提升性能:由于初始内容是服务器渲染的,用户可以更快地看到页面,减少了首次内容绘制(FCP)时间。

提高 SEO

更好的用户体验

(5)使用hydrate渲染互动性界面

1、创建clien.js

ReactDOM.hydrateRoot: 该方法来自 React 18,是为了将服务端渲染的内容与客户端 React 代码 “结合”。通过 hydrateRoot,React 可以在客户端接管已经在服务端生成的静态 HTML,并使其变得交互式。

document.getElementById('root') 获取了页面上的 <div id="root"></div>,React 的组件会渲染到这个元素中。

1
ReactDOM.hydrateRoot(document.getElementById('root'), <Home />);

里面还需包含和server.js中一样的JSX代码

2、在server.js中包含client路径
1
2
3
4
5
const clientJS = readFileSync(`${__dirname}/client.js`, 'utf-8');

else if (pathName === '/client.js') {
res.writeHead(200, { 'Content-type': 'application/javascript' });
res.end(clientJS);
3、在HTML中

中间的两个引入是搜索 babel cdn和react cdn来引入的

  • Babel:这是 Babel 的独立版本,用于在浏览器中直接编译和转译 ES6+ 和 JSX 代码。
  • React (UMD Module):这个脚本引入了 React 库,它是一个 JavaScript 库,用于构建用户界面。通过这个 CDN,你可以在浏览器中使用 React 编写组件。这是 UMD (Universal Module Definition) 版本的 React,它可以直接在浏览器中使用,而无需模块打包工具(如 Webpack)。这是开发环境的版本(react.development.js),它包括额外的调试信息,方便开发和调试。
  • ReactDOM (UMD Module):这个脚本引入了 ReactDOM 库,它是 React 的一部分,负责将 React 组件渲染到实际的 DOM 中。它允许你把 React 的虚拟 DOM 转换为浏览器的实际 DOM。同样,这是 ReactDOM 的 UMD 版本,允许你直接在浏览器中使用 ReactDOM.render()ReactDOM.hydrateRoot() 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
<div id="root">%%%Content%%%</div>

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>

<script type="text/babel" src="/client.js"></script>
</body>

react课程24-SSR概念引入及手写
http://example.com/2024/09/29/react课程24-SSR概念引入及手写/
Author
Yaodeer
Posted on
September 29, 2024
Licensed under