Respo 的服务端渲染

字节探雪使
• 阅读 2834

这篇文档是关于 Respo 服务端渲染(SSR)方案的一个介绍
最新内容参考 GitHub 的英文文档 https://github.com/Respo/resp...

因为 Respo 也是基于 Virtual DOM 的方案, 所以也能做服务端渲染,
为了方便, 渲染过程用的是 Planck, 而不是直接调用 Boot.
Respo SSR 的内容是承接前面的 Vue SSR 以及渐进首屏渲染的.

在前面已经完成了 ssr-stages 这个仓库可以演示:
https://github.com/Respo/ssr-...
后面我还用 http://tiye.me/ 做了一个测试, 基本上已经稳定了.

思路

原先我们觉得 React 服务端渲染就是在服务端渲染第一屏, 返回给浏览器,
但是这不能解决一些稍微复杂的问题, 比如说, 并不渲染整屏,
比如说服务端性能有限, 只渲染头部, 或者只想渲染一个 Shell 的页面,
甚至可能由于对浏览器 API 依赖, 某些局部是无法渲染的,
可能还有 SSR 相关的因素, 影响到这个页面的配置,
于是服务端渲染的首屏其实和前端的首屏, 往往是存在不一致的.

那么我觉得首屏其实是一个 patch 操作, 因为服务端渲染内容和客户端不一样,
既然要 Patch, 就需要有两个 Virtual DOM 用来产生 Diff,
所以我的办法就是让前端伪造一份与 HTML 相对应的 Virtual DOM,
至于怎么生成, 需要用户的业务代码当中完成, 一般还是通过数据控制的.
其实后端渲染相当于前端渲染内容的局部, 所以通过 if 等函数控制下就好了.

由于服务端渲染不方便绑定事件, 特别是不冒泡的事件,
那么我假设服务端 HTML 没有事件, 于是伪造的 Virtual DOM 就要去掉事件,
前端进行 patch 时, 再把事件全部绑定上去,
而这一个功能对于 DOM diff 来说是支持的功能之一, 因而很简单.

另一个要注意的是前端也许需要兼容多个版本的服务端渲染,
因为服务端可能进行控制, 只渲染局部, 或者不渲染, 而前端代码只有一份,
所以伪造的 Virtual DOM 需要自动选择, 当然也需要一些标记,
比如我在 <head> 中放置一个 <meta> 标签, content 属性中写一些信息.
然后前端代码就可以根据这个信息识别, 服务端生成的是哪个版本的 Virtual DOM.
当然, 也许写在 Store 当中也是一个办法, 只是要处理下没有 Store 的情况.

实现

我给了一个例子演示具体的方案:

(defonce global-states (atom {}))

(defn -main []
  (if (not (empty? ssr-stages))
    (let [target (.querySelector js/document "#app")]
      (falsify-stage!
        target
        (mute-element
          (render-element
            (comp-container @store-ref ssr-stages)
            global-states))
        dispatch!)))
  (render-app!)
  (add-watch store-ref :changes render-app!)
  (add-watch states-ref :changes render-app!))

其中具体的调用, 大概是这个意思:

  • (comp-container store level-of-ssr) 用来生成组件

  • (render-element component global-states) 用来渲染组件

  • (mute-element element) 移除掉组件中的事件

  • (falsify-stage! target element dispatch!) 在内部伪造 Virtual DOM

这样一个过程完成之后, Respo 就认为前端已经有 Virtual DOM 的状态了,
然后再渲染时, 就不在使用 mount, 自动进入到 Patch 的模式当中.
因而首屏渲染的问题基本上就解决了.

小结

目前 React 和 Vue 都没有这个功能, 他们都支持强制覆盖掉本地的 DOM.
其实也是个办法, 除了一些动画的细节会被破坏.. 以及可能有额外的抖动,
希望未来这可以是一个很多框架都支持的功能.

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Wesley13 Wesley13
4年前
SSR再好,也要有优雅降级策略哟~
1、相关概念CSR:客户端渲染(ClientSideRender)。渲染过程全部交给浏览器进行处理,服务器不参与任何渲染。页面初始加载的HTML文档中无内容,需要下载执行JS文件,由浏览器动态生成页面,并通过JS进行页面交互事件与状态管理。SSR:服务端渲染(ServerSideRende
Wesley13 Wesley13
4年前
VBox 启动虚拟机失败
在Vbox(5.0.8版本)启动Ubuntu的虚拟机时,遇到错误信息:NtCreateFile(\\Device\\VBoxDrvStub)failed:0xc000000034STATUS\_OBJECT\_NAME\_NOT\_FOUND(0retries) (rc101)Makesurethekern
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
4年前
Linux日志安全分析技巧
0x00前言我正在整理一个项目,收集和汇总了一些应急响应案例(不断更新中)。GitHub地址:https://github.com/Bypass007/EmergencyResponseNotes本文主要介绍Linux日志分析的技巧,更多详细信息请访问Github地址,欢迎Star。0x01日志简介Lin
字节探雪使
字节探雪使
Lv1
时间像奔腾澎湃的急湍,它一去无还,毫不留恋。
文章
3
粉丝
0
获赞
0