React + Express实现极简SSR的原理

2023-11-26 13:31:23 浏览数 (2)

记得在刚开始写代码的时候,那时候做一个网页,用的是PHP,页面内容使用php配合template直出,以为哪个就是一个web开发的全部,不料,react,vue的出现,迅速打破了web开发的体验,如实csr一时间成了前端开发中舆论套路的焦点,随后各种各样的前端开发框架出现,大多数是csr。

代码语言:javascript复制
UI = Render(State)

我们为什么需要SSR

从后端拿到数据,在本地渲染出页面,当然这中间还有 虚拟Dom等等,但是本文都不是本文的重点,本文旨在极简的实现一个 SSR,为什么要这么做,因为csr对于一些场景来讲,相对于ssr是有其不足的。具体的一些对比,我将其放在了下面的表格中:

服务端渲染(SSR)

客户端渲染(CSR)

加载速度

通常更快,因为服务器直接发送渲染好的页面,浏览器可以立即显示。

通常较慢,因为需要加载JavaScript文件后才能渲染页面内容。

SEO优化

更有利于SEO,因为搜索引擎可以抓取渲染好的页面内容。

不利于SEO,因为搜索引擎可能无法等待JavaScript渲染内容。

首屏时间

首屏时间短,用户感知到的加载速度更快。

首屏时间长,需要等待JS下载和执行。

资源利用

对服务器资源要求较高,因为渲染工作在服务器上完成。

对客户端资源要求较高,渲染工作在用户设备上完成。

可交互性

页面到达用户浏览器时已经是渲染好的,但需要客户端脚本激活后才能交互。

页面加载后即可交互,因为所有渲染和脚本执行都在客户端完成。

缓存策略

可以利用服务器端缓存来提高响应速度。

主要依赖浏览器缓存。

开发复杂性

通常更复杂,需要处理服务器和客户端代码的同步问题。

相对简单,因为所有逻辑都在客户端处理。

用户体验

用户可以更快看到页面内容,但完全交互可能需要更多时间。

用户可能会看到加载指示器,直到页面完全可用。

更新部署

更新可能需要重新部署服务器端代码。

更新通常只需要替换静态文件。

可维护性

需要维护服务器和客户端两套代码,可能增加维护成本。

只需维护客户端代码,维护相对简单。

可以看到,服务端渲染(SSR)有着客户端渲染(CSR)不可比拟的一些优势,如,对SEO更加友好,用户可以更快的看到内容,首屏时间短等等,但是CSR也并非一无是处,他实现简单,对服务器压力也轻等等。

学习本文,你可以学会基于react express极简实现一个SSR,这里也提供一个思路,比如vue koa可以不可以,当然也是可以的,这个处理的流程是一致的。

开始动手实现

基于react express实现服务端渲染,其大致的流程如下图所示:

其中,最为复杂的地方就是 reactApp 和 ReactDOMServer 那块的交互,所谓的服务端渲染,就是在服务端把dom都渲染好,直出给到客户端显示,而所谓的csr,就是这个dom的构建过程在客户端本地。

具体的实现步骤

假设我们已经有了一个react的应用,app.js的代码如下:

代码语言:javascript复制
import React from 'react';

const App = () => {
    return <div>Hello, SSR!</div>;
};

export default App;

那么,这里面省略一个事件处理如 ,onClick等等。那么,要做到这个极简的是在服务端渲染的,如果试下呢?

其实不难,我们在服务端这样玩:

代码语言:javascript复制
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App';

app.get('*', (req, res) => {
    const html = ReactDOMServer.renderToString(<App />);
    res.send(`
        <!doctype html>
        <html>
            <head>
                <title>SSR with React</title>
            </head>
            <body>
                <div id="app">${html}</div>
                <script src="/bundle.js"></script>
            </body>
        </html>
    `);
});

但是,我们似乎忽略了一个问题,一个网页是需要有交互的,比如onClick等时间,服务端直出dom似乎会”忘掉”这些,那么怎么办呢?这时候就需要ReactDOM.hydrate了,这个过程称之为唤醒。其大致的流程如下,其目的就是让页面重新变的可交互。

当然, 在 hydration 过程中,React 会对比服务器渲染的 HTML 和 React 组件树。如果发现差异,React 会尝试以最小的代价更新 DOM,以确保客户端的 DOM 与 React 组件树同步。然而,React 假设服务器端和客户端渲染的输出是一致的,如果不一致,可能会导致 hydration 错误。

这就是实现 React SSR 的基本步骤。用代码简化表示如下:

代码语言:javascript复制
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.hydrate(<App />, document.getElementById('app'));

在 React 18 中,ReactDOM.hydrate 已经被 hydrateRoot 替代,后者是与新的并发特性兼容的,在具体实现的时候,需要关注下API的变化。

总结

当然,在我们实际项目中可能会更复杂,绝对不是一个简单的hello world,比如涉及到:

  • 路由处理
  • 数据预取
  • 状态管理

因此,我们的项目如果要考虑选型使用SSR,建议采用成熟的框架,如react可以使用 next.js ,vue可以采用 nuxt.js ,这些都是非常成熟的,且经过比较多大型项目验证过的框架,可以放心使用,而且在腾讯云上也可以非常方便的体验,搜索 腾讯云 快速部署 Nextjs 框架 ,就可以体验。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞