获取中...

-

Just a minute...

关于ssr相关的介绍,可以移步之前的一篇博文,本文不再赘述

日常工作中,我们可能都接触过ssr,不过我们可能通常是借助于框架(例如Next.js)的支持来完成ssr。今天我想尝试,摆脱高度封装的前端框架,只依赖react相关的库,来实现ssr。

本篇代码 pnpm i安装依赖,npm run server启动服务

环境:node 20.12.0 react和react-dom版本均为18.3.1

参考文献:知乎专栏:SSR原理与实践

正文

我们的目的,是本地的8080端口起一个node服务,然后当我们访问localhost:8080的时候,服务端能返回给我们一个页面,。在拿到页面之后,浏览器会对页面进行水合,从而使得页面可交互。

首先,我们先安装一下依赖。我比较喜欢pnpm(节省磁盘空间,避免幽灵依赖),所以我直接在命令行敲pnpm i react react-dom express 。安装react(将jsx转为虚拟dom),react-dom(将虚拟dom转成dom),express(用于起一个web服务器)

然后我们新建三个文件,分别是server.js,index.js,App.jsx

App.jsx里面,我们就简单实现一个组件吧,然后要用commonjs的方式去引入和导出(因为我们是极简版本,甚至都没有经过打包构建流程,为了能让node端识别,就直接按cjs规范写了)

index.js里面,我们要去写用于客户端执行的代码,我们暂且随便在里面console.log一句话吧,用于证明index.js被成功加载。

本期的重头戏来了,server.js,不多bb先上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const express = require("express");
const App = require("./app.jsx");
const ReactDom = require("react-dom/server");
const React = require('react')

const server = express();
server.use(express.static('.'))
server.get("/", function (req, res, next) {
const elementString = ReactDom.renderToString(<App />);
const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>my react ssr</title>
</head>
<body>
<div id="root">
${elementString}
</div>
</body>
</html>
<script type="text/javascript" src="index.js"></script>`;
res.send(html);
});

server.listen(8080);

对于访问根目录的请求,我们依旧是通过cjs的require,拿到app.jsx的内容。然后借助react-dom/server的api renderToString,将jsx组件转成html字符串 。

接下来就是拼模板啦,直接copy模板,然后把得到的html字符串放到模板字符串中间,并且在最后写一个script标签,加载未来可期的index.js。然后返回response就可以了

然后为了解决node不认识jsx的问题,我们又装了bable的一系列包。依旧是用pnpm安装@babel/cli,@babel/core,@babel/node,babel/preset-env,@babel/preset-react。然后在package.json添加一个script,

1
2
3
"scripts": {
"server": "babel-node server.js"
}

然后我们就可以通过npm run server,来启动服务了。打开浏览器,访问localhost:8080,可以看到页面正常展示。但是打开控制台,发现index.js没加载出来,404了。是因为请求localhost:8080/index.js 这个静态资源路径,express是不知道你要什么的。需要通过express.static(pathxxx)中间件,来告诉express,以pathxxx作为静态资源目录。例如我这里把index.js放在了根目录,那pathxxx就是“.”就可以了。

再次重启服务,打开控制台,看到index.js正常被加载,打印出了我们想要的东西。

本次暂时只实现服务端渲染的部分,后续客户端水合,且听下回分解

相关文章
评论
分享
  • 动手实现react-ssr 2

    仓库链接:本篇代码 运行方法参考readme,请使用pnpm,因为本次使用的rspack尚未推出1.0版本,预计后续可能会有很多breakchange,所以lock文件至关重要,而我只上传了pnpm的lock,非常抱歉。 环境:no...

    动手实现react-ssr 2
  • 从invalid hook call报错说到npm install相关

    遇到了invalid hook call报错上周,业务下游的同事反馈了一个生产问题,说我们传的值有问题,领导让我帮忙排查一下。我最近一直没做那个项目相关的需求,打开那个项目切到release分支,拉代码,npm i然后启动,结果就白屏...

    从invalid hook call报错说到npm install相关
  • React中副作用的执行时机

    为什么一定要useEffect?之前看到过,说不要把副作用直接写在函数式组件的函数体内,需要用useEffect把副作用包裹起来。我当时的理解就是,函数组件重新渲染的话,整个函数都会被执行一遍。如果我就想让一个副作用,每次组件渲染都重...

    React中副作用的执行时机
  • 聊聊react与函数式编程

    react不是魔法 今天我想来聊一聊函数式编程,和它在react中的体现。 何为函数式编程我们可以把函数式编程理解成一种范式,一个规范。纯函数是函数式编程的关键概念,函数式编程希望我们尽可能多地使用纯函数。正是依赖于纯函数的特点,...

    聊聊react与函数式编程
  • react的一些坑

    记录一些刚写react踩过的坑吧,想到多少就写多少 从一个工作中的需求开始有个需求是,点击按钮出来一个弹窗。本来弹窗有个关闭按钮,但是UED在视觉稿上面加了行字,“点击关闭按钮或弹窗外的其他地方,关闭弹窗”。我想了想,合理,避免有...

    react的一些坑
  • 使用react的一些心得与感想

    刚忙完公司的新人训练营,9个人的团队2周完成一个小项目。我负责用remax开发一个微信小程序。remax就是蚂蚁的一个开源框架,让开发者能用react的语法去开发微信小程序。开发体验整体来讲非常不错,感觉也加深了我对react的理解...

    使用react的一些心得与感想
  • 基于tapable来模拟webpack插件机制

    前两天看到ByteFE公众号发了篇文章,从源码去讲webpack。我之前也从很多方面去学习webpack,只是源码一直没太看得进去,这一次我想仔细地读一读。 简要介绍tapable说实话,之前看webpack源码一直没看的太懂,...

    基于tapable来模拟webpack插件机制
  • 深入js——作用域,作用域链,执行栈(一)

    最近在补js基础。当初自学js的时候,总是感觉学的不扎实。只能说不去上手,再怎么死读书,也理解不了。积累了经验,然后自己去思考,这个时候再去看理论,就容易理解了。 感觉工作一年以来,确实学到了很多,但是过于专注于应用方面的知识,反倒...

    深入js——作用域,作用域链,执行栈(一)
  • webpack运行时代码简要分析

    开个坑,主要也是怕自己后面忘了 简单写写,有空了补上 __webpack_modules是一个数组,每个元素都是一个函数,函数接受三个参数:第一个参数module好像没用到,第二个是一个对象(会把本模块要导出的属性,赋值给这个对象),...

    webpack运行时代码简要分析
  • webpack动态加载原理简述

    为什么需要动态加载上一篇讲我写webpack针对markdown的loader的时候,提到了希望能动态加载以优化性能。篇幅原因没有展开说,打算单独写一篇文章讲一下。 当我们访问网站的时候,浏览器会向服务器请求页面资源。首先请求的当然是...

    webpack动态加载原理简述
Please check the parameter of comment in config.yml of hexo-theme-Annie!