如何实现一个简单的SSR服务

70 阅读1分钟

客户端服务渲染问题

CSR客户端渲染问题:渲染资源浪费、seo没办法优化服务端渲染问题
SSR服务端渲染问题:服务压力大、开发难度大、前后都需要维护

渲染流程

SSR:流程server ---rendered html ---browser
CSR: 流程server -----empty html + JS ---browser executes js ----rendered html

两大渲染主要用到组件

renderToString----服务端

hydrateRoot-----客户端

主要框架与组件 express、vite

实现一个简单server Main主调

import express from 'express';
import fs from 'node:fs';
 //实现一个服务ss中间件
 import { createServer } from 'vite';
 // 初始化中间件
 const  vite = await createServer({
  server: { middlewareMode: true},
  appType: 'custom'
 });
const app = express();
// 挂载vite中间件
app.use(vite.middlewares);
// 拦截请求
app.use('*', async (req, res)=>{
// 使用vite模块加载
const template = await vite.transformIndexHtml(
  req.url,
  fs.readFileSync('index.html', 'utf-8')
)
// 加载rend渲染器
const { RenderHtml } =await vite.ssrLoadModule('rend.jsx')
 const html = RenderHtml();
 const newTemplate = template.replace(`<!--app-html-->`, html)
 // 与终端内容对应
  res.send(newTemplate);
})
app.listen(3000,()=>{
  console.log('http://127.0.0.1:3000')
})
 

实现一个react的dom挂载能力

// 客户端入口
import React from "react";
import { hydrateRoot } from 'react-dom/client';
import { Hello } from "./html/react/hello";
hydrateRoot(document.getElementById('root'),<Hello/>)

实现一个动态数据hook功能

import React, { useState} from 'react'
import styles from '../react/index.module.css'
export const Hello = ()=>{
  const [count, setCount] = useState(0)
  return <div className={styles.hello}>
    hello
    <button onClick={()=>{
      setCount((c)=>count + 1)
    }}>{count}</button>
  </div>
}

实现一个react的挂载

// 客户端入口

import React from "react";
import { hydrateRoot } from 'react-dom/client';
 import { Hello } from "./html/react/hello";

 hydrateRoot(document.getElementById('root'),<Hello/>)

实现一个index的html页面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="root">
    <!--app-html-->
  </div>

  <script type="module" src="./main.jsx"></script>
</body>
</html>