实现简易 React SSR 框架

实现简易 React SSR 框架

框架依赖

  • express
  • react
  • react-dom

创建一个 node server

使用 express 创建一个 node server

js 复制代码
import express from 'express'
import handlerSsr from './ssr'

const app = express()
const port = process.env.PORT || 3000

app.use(express.static('public'))

app.get('*' , (req, res) => {
  // 处理 SSR 逻辑
  return handlerSsr(req, res)
})

app.listen(port, () => {
  console.log(`Server started on http://localhost:${port}`)
});

创建一个根组件

js 复制代码
// client/App.js
import React from 'react';

function App(props) {
    return <div>Hello World!</div>;
}

export default App;

处理 SSR 逻辑

主要分为以下几个步骤:

  1. 解析请求:确定当前请求的URL和任何查询参数。
  2. 获取数据:对于动态内容,您可能需要从数据库或外部API获取数据。
  3. 渲染React组件树:使用收集到的数据渲染您的React组件树。
  4. 序列化HTML:将渲染后的React组件转换为静态HTML字符串。
  5. 发送响应:将最终的HTML字符串发送回浏览器。
js 复制代码
import App from './App'

export const handlerSsr = (req, res) => {
  // 处理请求
  const url = req.path

  const handleRequest = async () => {
      const data = await getDataPage(url);

      if (!data) {
          res.statusCode = 404;
          res.end('Not Found');
          return;
      }

      const html = renderPage(data);
      res.write(html);
      res.end();
  };

  // 获取数据(在真实场景中,这部分很可能是异步的)
  const getDataPage = async (url) => {
      // 模拟从数据库或API获取数据的行为
      switch (url) {
          case '/':
              return { title: 'Home', message: 'Welcome home!' };
          case '/about':
              return { title: 'About Us' };
          default:
              return null;
      }
  };

  // 渲染React组件树
  const renderPage = (data) => {
      const renderedContent = ReactDOMServer.renderToString(
          <App {...data} /> // 将数据作为props传递给App组件
      );

      return `
        <!doctype html>
        <html>
            <head>
                <meta charset=utf-8/>
                <title>${data.title}</title>
            </head>
            <body>
                <div id="root">${renderedContent}</div>
                <script type="text/javascript" src="index_bundle.js"></script>
            </body>
        </html>
    `;
  };

  handleRequest()
      .catch((err) => {
          console.error(err.stack);
          res.status(500).send('Something broke!');
      });

}
相关推荐
上海懒图科技3 小时前
工厂厂区电子地图定位导航:厂区人车精准定位,安全合规双保障
前端·arcgis·vue
西安小哥4 小时前
端侧跑大模型,真正的门槛不在参数量:一次 596 秒到 10 秒的压缩路径复盘
前端·人工智能
陈随易4 小时前
Cloudflare 出钱,Vite 团队挑人,44 个维护者分 30 万美元
前端·后端·程序员
恋猫de小郭5 小时前
Flutter THLC 的 WebView 滚动终于从 70 FPS 提升到 120 FPS
android·前端·flutter
严肃小白兔5 小时前
TanStack Router 更新构建工具链:Node.js 兼容性、路由分割与前端工程实践
前端·node.js·状态模式
IT_陈寒6 小时前
Vue这个奇葩的响应式问题让我加班到凌晨
前端·人工智能·后端
风骏时光牛马6 小时前
功能可用性自动化测试验证
前端
LucianaiB16 小时前
【元宝搜索开发者征文大赛】AI时代,学得慢就不用学?用元宝搜索打造一个教程保质期,确保每一个教程符合你的现状
前端·人工智能·ai编程
excel16 小时前
JavaScript 对象池:减少高频对象创建与 GC 压力
前端
陈随易18 小时前
纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS
前端·后端·程序员