Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

MJingv/ssr-react

Repository files navigation

ssr-react

准备工作

概念先行

  • CSR 客户端渲染

页面初始加载的 HTML 页面中无网页展示内容,需要加载执行JavaScript 文件中的 React 代码,通过 JavaScript 渲染生成页面,同时,JavaScript 代码会完成页面交互事件的绑定

  • SSR 服务器端渲染

用户请求服务器,服务器上直接生成 HTML 内容并返回给浏览器。服务器端渲染来,页面的内容是由 Server 端生成的。一般来说,服务器端渲染的页面交互能力有限,如果要实现复杂交互,还是要通过引入 JavaScript 文件来辅助实现。

  • 同构

我们把页面的展示内容和交互写在一起,让代码执行两次。在服务器端执行一次,用于实现服务器端渲染,在客户端再执行一次,用于接管页面交互,

为什么要ssr?

  • 加快TTFP(Time To First Page)
  • 增加SEO

实现原理

ssr

  • 虚拟dom
  1. 虚拟 DOM 是真实 DOM 的一个 JavaScript 对象映射
  2. 在服务器,我可以操作 JavaScript 对象,判断环境是服务器环境,我们把虚拟 DOM 映射成字符串输出;
  3. 在客户端,我也可以操作 JavaScript 对象,判断环境是客户端环境,我就直接将虚拟 DOM 映射成真实 DOM,完成页面挂载。
  • ssr差异 (C vs S)
  1. 代码:只有【组件】代码可以共用,路由不同【服务器用StaticRouter】【客户端用BrowserRouter】
  2. 异步获取数据:在服务器端,页面一旦确定内容,就没有办法 Rerender。判断路由,用promise队列获取所有数据ready再渲染
  3. 跨域:客户端有同源限制,可用【 express-http-proxy 】做代理,服务器端无限制
  4. 打包:
 1. 入口不同
 2. server 用 target: node 
 3. server 用【webpack-node-externals】排除打包node已有的包
 4. css不同:客户端用 css-loader 和 style-loader,css-loader 不但会在 DOM 上生成 class 类名,解析好的 CSS 代码,还会通过 style-loader 把代码挂载到页面上。
 5. 服务器端 css 用【 isomorphic-style-loader】拿到返回的样式代码,然后以字符串的形式添加到服务器端渲染的 HTML 之中

React-ssr关键api

将React Component转化为HTML的字符串 都接受一个React Component参数,返回一个String

  • renderToString

将React Component转化为HTML字符串,生成的HTML的DOM会带有额外属性:各个DOM会有data-react-id属性,第一个DOM会有data-checksum属性。

  • renderToStaticMarkup

同样是将React Component转化为HTML字符串,但是生成HTML的DOM不会有额外属性,从而节省HTML字符串的大小。

  • ps
  1. 如果使用renderToString渲染组件,会在组件的第一个DOM带有data-react-checksum属性,这个属性是通过adler32算法算出来:如果两个组件有相同的props和DOM结构时,adler32算法算出的checksum值会一样,有点类似于哈希算法。
  2. 当客户端渲染React组件时,首先计算出组件的checksum值,然后检索HTML DOM看看是否存在数值相同的data-react-checksum属性,如果存在,则组件只会渲染一次,如果不存在,则会抛出一个warning异常。也就是说,当服务器端和客户端渲染具有相同的props和相同DOM结构的组件时,该React组件只会渲染一次。



attention

1.npm install --save-dev babel-loader@^7


note

  1. react-dom/server API renderToString 将组件转化为字符串做最基础的服务器端渲染
  2. vDOM是真实dom的js对象映射
  3. 用到jsx记得引入react
  4. ssr路由只发生在第一次

node代理服务器

  1. express-http-proxy

加载css

服务器端渲染

  1. webpack利用isomorphic-style-loader

客户端端渲染

  1. webpack利用style-loader及css-loader

redux数据管理

服务器端渲染

问题:不会运行componentDidMount,store一直为空,不会获取数据

  1. loadData:在server渲染之前,把数据加载好
  2. 路由 match 动态加载loadData
  3. 模拟路由匹配行为: map some push
  4. react-router-config match-routers 进行多级路由匹配
  5. 利用promise异步加载数据

最终解决方案流程:

  1. 创建空store
  2. matchRouters循环匹配并查看是否有loadData
  3. 执行loadData,放入promise
  4. promise.all成功后,获取全部数据成功
  5. 结合路由、请求、数据生产html返回给用户

客户端渲染

  1. store更新
  2. 页面重新渲染出数据

脱水&&注水

  1. 注水:将数据存入windows.context
  2. 脱水:从windows.context拿数据

webpack配置

热更新

  1. 自动打包 webpack --config webpack.server.js --watch
  2. 自动重启服务器 nodemon --watch --exec
  3. 打包&&重启服务器 npm-run-all

优化

  1. webpack-merge 复用相同的配置

注意

  1. 配置执行顺序:从下到上,从右到左

路由

  1. 客户端路由渲染用BrowserRouter
  2. 服务器端路由渲染用StaticRouter,通过req.path动态获取路由路径
  3. 利用react-router 的link切换路由

中间层

浏览器=》node-server=》c++/java-server

  1. node服务器只负责拼装并返回页面,java/c++服务器负责底层数据处理

问题:ssr无法正常render绑定事件

同构:一套react代码先在server执行,再在client执行

  1. 用script加载文件
  2. 静态资源文件用static中间件 app.use(express.static('public'))
  3. 将在客户端运行的代码也用webpack打包后放到public的index下
  4. 用hydrate来做client渲染
  5. 流程:
  • 服务器运行react代码渲染出html
  • 发送html给浏览器
  • 浏览器接受内容并展示
  • 浏览器加载js文件
  • js中的react代码在浏览器中重新执行
  • js的react代码接管页面操作

SEO

  1. 搜索引擎只认识html,客户端渲染js无法拿到数据,全能搜索引擎会根据全部数据来分析。
  2. 优化 title description 提升吸引力、转化率
  3. 提升seo:网站组成:文字【增加原创性】 链接【提升外部链接、增强内部链接】 多媒体
  4. react-helmet 定制化 title description
  5. 加nginx分析是否为蜘蛛,蜘蛛则走预渲染prerender

About

a ssr-react project 🔍(react+ssr)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /