vue ssr的hydration问题

news2024/11/15 3:30:17

 我的网站百家饭OpenAPI平台是vuepress写的,前段时间我还写了个专栏讲了vuepress2.0教学。

最开始我们的网站是类似公司网站的情况,以介绍为主,后来又加了一个openapi编辑器,编辑器主要在一个页面里面,vuepress还勉强可以用,虽然其中出现了一些小的问题,但是还是被我们坚持下来了,但是最近遇到的一个问题,让我们不得不在部分页面改用别的框架来搭建一个完全独立的部分。

这就是vue ssr的hydration问题。

(以下vue都包含vue,vuepress,nuxt等vue体系下的框架)

什么是ssr

ssr是server side render的简称,就是服务器端渲染,我们知道最开始html就是服务器传输给浏览器的,只是近年因为js渲染的崛起,像vue这些技术都是通过vdom在客户端进行页面架构,服务器端实际传输的以js代码为主。

但是这种方式第一是需要更长的时间来渲染页面(先传代码,再渲染,耗时长),第二是对搜索引擎不友好(搜索引擎只能看到代码),所以像vuepress这种以内容为主攻的框架肯定是需要部分核心内容要能够直接在服务器上进行渲染,保证内容搜索引擎也能读取。这就用到了ssr。

ssr通过在服务器端进行部分组件的编译,还原成html,使得搜索引擎拿到的就是html的具体内容。这就是ssr的功能。

ssr看起来是开历史的倒车,但我觉得还是有很多有益的地方,因为js渲染之后,其实出来了很多以此为基础的vue组件,例如鼎鼎大名的elementui,你不用vue就没法用到这些组件,如果要走原始的html编程的老路,这才是最麻烦的事情,对效率的打压在50%以上。

vue ssr的难点:如何部分ssr,又能在客户端保留vdom的优势

上面我们讲了ssr,其实完全ssr做出静态页面是一点问题没有的,但是从现代网页的设计来看,大量客户端动态操作,又不得不依赖vdom等技术来实现(仅讨论vue的情况)

揭秘 Vue 中的 Virtual Dom - 掘金 (juejin.cn)icon-default.png?t=N176https://juejin.cn/post/6844903874688450568于是,vue的做法是在ssr生成的html的基础上,再同时生成一个js文件,js文件里同时保存在客户端能再现渲染的js版本,js版本里是通过vdom进行渲染的操作函数,而html是ssr后的结果。

当浏览器拿到这两个东西之后,浏览器就开始重新执行一遍vdom的生成过程,并在此基础上去执行客户端动态操作。

 那一旦出现不匹配的情况,那dom渲染就会出问题,部分界面组件会重复渲染,控制台会报错

hydration completed but contains mismatches.

一般的ssr需要由nodejs做后端服务器,这里有一个较官方的教程

Server-Side Rendering (SSR) | Vue.js (vuejs.org)icon-default.png?t=N176https://vuejs.org/guide/scaling-up/ssr.html在这种情况下,ssr mismatch不经常出现,但是有可能由于例如内含精度太细的时间戳等信息,导致服务端和客户端两次生成的时间不匹配等情况造成。

vuepress的ssr

当ssr具体在vuepress里体现的时候,情况又发生了一些变化,由于vuepress编译md文件生成vue,再由vue生成静态文件的做法,vuepress的ssr实际是在编译过程中发生的一个前置步骤,已经失去了动态render的功能,退化成了ssg(server side generation),也就是说html是一个预先编译好的静态内容。

ssr和托管服务器的不兼容问题

ssr要在客户端重新match这个特性,除了官方提到的问题之外,我们在和golang http server配合的过程中还发现了其他一些问题,这些问题是因为和golang template一起使用造成的:

1)html不能再优化,这个问题对我们也造成了一些困扰,他的来源是vue这个hydration除了依靠html结构之外,对html的注释也有格式要求,可能要靠注释去匹配动态段

类似这里面绿色的注释部分,而golang在通过template处理之后,这些内容即便只是静态内容,也会被默认优化去掉。造成了最开始一段时间我们死活找不到问题所在。 

这个问题可能和其他服务器也有关系,我猜想一些cdn缓存服务器的默认优化方案也会造成类似的问题。

2)无法再通过注入实现更多动态内容的展示

随着百家饭平台加入API评论等功能,我们需要的动态内容静态化展示功能越来越多,比如优质评论等内容,实际是类似blog的动态输入内容,但是呈现上要以静态页面的形态。

我们原本设计,在vuepress输出的页面中,将内容部分替换成golang template的替换符,然后把生成的文件作为golang http server的template文件,再对其中的替换内容进行动态替换,达到动态展示页面的目的。

 这个替换过程中,由于实际的模板内容只在html被动态替换,而对应的js文件中的没有被正确替换,造成了客户端因mismatch导致渲染错误。

(下图可见,如果在vue中定义了golang template,则对应会在html和js中都存在一份)

 ssr上述不兼容问题的解决尝试

知晓了问题之后,我们大概做了以下尝试,但均告失败:

1)使用dehydration插件vuepress/vuepress-plugin-dehydrate: Dehydrate HTML files in VuePress. (github.com)icon-default.png?t=N176https://github.com/vuepress/vuepress-plugin-dehydrate

问题:

  1. 这是个vuepress插件,不是vuepress2.0插件
  2. 他会做页面级的处理,比如一个页面标记成noScript之后,所有该页面的js部分就不再生成了,这样页面的动态js功能也同时失去了,完全变成了静态页面

2)尝试把js里面的模板部分也进行解析

上面的mismatch问题是因为html里的模板被解析了,但是js没有解析,那是不是可以通过把js部分也解析掉,使得js也保持一致,这样就没有问题了呢

问题:

  1. 需要模板化解析的页面通常是动态页面,要使得js也动态解析,实际上,要把html里对js的script引用变成动态化,这个过程要求对vuepress的html打包部分进行插件化处理。修改难度较大
  2.  js文件实际是一次二次请求,会造成服务器动态内容解析的性能损耗翻倍。
  3. 也可以将script引用,直接改成js内容内嵌到html中,但js部分实际又用于vuepress的本地化跳转等流程,需要在其他页码中也引用,所以内嵌也不是一个好方案。

3)使用一款叫vue-lazy-hydration的插件

maoberlehner/vue-lazy-hydration: Lazy Hydration of Server-Side Rendered Vue.js Components (github.com)icon-default.png?t=N176https://github.com/maoberlehner/vue-lazy-hydration这款插件按介绍可以标注部分组件延后hydrate,里面有never选项,表示不进行hydrate,但是遗憾的是这款插件和vuepress不兼容。

4)换用nuxt作为整体框架

问题:

  1. 太麻烦
  2. nuxt作为vue体系,似乎也采用了hydration机制,如果不用nodejs应该是同样的问题

至此,我们觉得解决这个问题似乎已经跨越了我们可以解决的难度了,于是有了以下一些结论,供遇到类似问题的同学参考:

  1. vuepress还是只适合静态内容展示,不要做动态blog
  2. 我对vue ssr的功能首先产生了怀疑,这样是不是只适用于用nodejs的小型项目?
  3. 我对vue ssr的性能也产生了怀疑,同样的内容要渲染两次

最后,这个问题通过使用一款叫lit的轻量级框架解决掉了,关于lit的使用介绍,我们会随着开发的进展逐步也介绍给大家。

PS:

写的过程中,突然觉得可以有这么个方案:

在app.vue中预留一个display:none的元素,里面放置需要用ssr来渲染给搜索引擎的内容:

<body>
    <div id="ssr" style="display:none">{{ .Content }}</div>
    <div id="app"></div>
</body>

因为vue挂载在app节点里,其他的都算静态内容,这样我们可以使用template去渲染一份给搜索引擎的,而用户侧内容还是由vue在客户端渲染,这也许是个方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Springboot系列】Springboot接管所有Controller,magic-api源码阅读

系列文章地址&#xff1a;Spring Boot学习大纲&#xff0c;可以留言自己想了解的技术点 最近在项目中使用了一个第三方的包 magic-api&#xff0c;节省了很多的时间&#xff0c;整体来说就是只用写sql就好了&#xff0c;不用写service&#xff0c;controller那些&#xff0c;全…

Flink从入门到精通系列(二)

3、Flink 部署 Flink 是一个非常灵活的处理框架&#xff0c;它支持多种不同的部署场景&#xff0c;还可以和不同的资源管 理平台方便地集成。 3.1、快速启动一个 Flink 集群 3.1.1、环境配置 Flink 是一个分布式的流处理框架&#xff0c;所以实际应用一般都需要搭建集群环境…

IO与NIO区别

一、概念 NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。 二、NIO和IO的主要区别 下表总结了Java I…

GM8773C 是一款 1:2 DSI 桥接芯片,可实现 4 路进 8 路出转换器功能、视频分离器功能。

GM8773C 是一款 1&#xff1a;2 DSI 桥接芯片&#xff0c;可实现 4 路进 8 路出转换器功能、视频分离器功能。芯片内集成了一个 4 路单一链路的 MIPI DSI 接收器和 8 路双链路 MIPI DSI 发送器。 接 收 器 每 路 可 以 支 持 到 2.0Gbps/lane &#xff0c; 可 以 最 高 支 持 到…

平面设计软件Corel CDR2023又开始放大招啦,CorelDRAW Graphics Suite 2023有哪些新增功能?

CorelDRAW 2023中文版即将于2023年3月14日&#xff0c;在苏州举行线上直播的2023新品发布会&#xff0c;本次发布会主题为“设计新生力&#xff0c;矢量新未来”。 发布会邀请思杰马克丁公司领导、Corel 中国区总经理分享思杰与 Corel 的合作模式及在 CorelDRAW 产品上推动历程…

JavaEE简单示例——Bean管理

简单介绍&#xff1a; 在这一章节我们会比较详细的介绍我们在之前的测试类中以及Bean管理XML配置文件中所使用到的类和方法&#xff0c;以及XML中配置的属性所代表的详细含义。以及之前我们反复提到但是一直没有详细的讲解的一个东西&#xff1a;容器。我们可以大致的有一个概…

react+antdpro+ts实现企业级项目四:注册页面实现及useEmotionCss的介绍

创建文件路径并注册register路由 在pages/User下创建Register文件夹并创建index.tsx文件 然后在config/routes创建register注册路由。注册完后&#xff0c;当在登陆页面点击注册按钮时就可以跳转到此注册页面而不会报404了。 export default [{path: /user,layout: false,rou…

PaddleOCR关键信息抽取(KIE)的训练(SER训练和RE训练)错误汇总

1.SER训练报错: SystemError: (Fatal) Blocking queue is killed because the data reader raises an exception 1.1.问题描述 在执行训练任务的时候报错 单卡训练 python3 tools/train.py -c train_data/my_data/ser_vi_layoutxlm_xfund_zh.yml错误信息如下&#xff1a; T…

初识C++需要了解的一些东西(1)

目录&#x1f947;命名空间&#x1f3c5;存在原因&#x1f3f5;命名空间定义&#x1f3a7;命名空间的3种使用方式&#x1f3c6;C输入和输出&#x1f31d;缺省参数&#x1f31c;缺省参数概念⭐️缺省参数分类☀️函数重载&#x1f525;引用&#x1f31a;引用概念&#x1f313;引…

LeetCode 热题 C++ 581. 最短无序连续子数组 617. 合并二叉树

581. 最短无序连续子数组 给你一个整数数组 nums &#xff0c;你需要找出一个 连续子数组 &#xff0c;如果对这个子数组进行升序排序&#xff0c;那么整个数组都会变为升序排序。 请你找出符合题意的 最短 子数组&#xff0c;并输出它的长度。 示例 1&#xff1a; 输入&am…

记录--Vue自定义指令实现加载中效果v-load(不使用Vue.extend)

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 网站效果演示&#xff1a;ashuai.work:8888/#/myLoad GitHub仓库地址代码&#xff1a;github.com/shuirongshu… 加载中思路分析 实现加载中效果&#xff0c;一般有两种方式: 第一种是&#xff1a;搞一…

双馈风力发电机-900V直流混合储能并网系统MATLAB仿真

MATLAB2016b主体模型&#xff1a;双馈感应风机模块、采用真实风速数据。混合储能模块、逆变器模块、转子过电流保护模块、整流器控制模块、逆变器控制模块。直流母线电压&#xff1a;有功、无功输出&#xff08;此处忘记乘负一信号输出&#xff09;&#xff0c;所以是负的。蓄电…

鉴源论坛 · 观模丨模型检查综述

作者 | 李建文 华东师范大学软件工程学院博导 版块 | 鉴源论坛 观模 01 模型检查的历史 模型检查是一种起源于20世纪70年代末的形式化验证技术。该技术最初由Edmund M. Clarke、E. Allen Emerson和Joseph Sifakis提出&#xff0c;他们因在模型检查领域的贡献而获得了2007年的…

无监督循环一致生成式对抗网络:PAN-Sharpening

Unsupervised Cycle-Consistent Generative Adversarial Networks for Pan Sharpening &#xff08;基于无监督循环一致生成式对抗网络的全色锐化&#xff09; 基于深度学习的全色锐化近年来受到了广泛的关注。现有方法大多属于监督学习框架&#xff0c;即对多光谱&#xff0…

【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建

【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建项目的逐步细分配置git环境创建项目后端前后端不分离写法-url访问路径解析资源安装vuevue文件后端解析数据发送到前端页面解析出来项目的逐步细分 匹配界面&#xff1a;需要用微服务实况直播&#xff1…

Lesson 9.1 集成学习的三大关键领域、Bagging 方法的基本思想和 RandomForestRegressor 的实现

文章目录一、 集成学习的三大关键领域二、Bagging 方法的基本思想三、RandomForestRegressor 的实现在开始学习之前&#xff0c;先导入我们需要的库&#xff0c;并查看库的版本。 import numpy as np import pandas as pd import sklearn import matplotlib as mlp import sea…

Flink学习-单词统计WordCount

WordCount&#xff08;流处理&#xff09;通过socket数据源&#xff0c;去请求一个socket服务&#xff08;9999&#xff09;,得到数据流然后统计数据流中出现的单词及其个数1.创建一个编程入口&#xff0c;生成环境StreamExecutionEnvironment streamEnv StreamExecutionEnvir…

嵌入式Linux驱动开发(二)LED驱动

1. Linux下LED驱动原理 与裸机区别在于&#xff0c;编写驱动要符合linux驱动框架规范。裸机直接对寄存器物理地址进行读写&#xff0c;linux下需要经过MMU。 1.1 地址映射相关概念 1&#xff09;MMU&#xff08;Memory Manage Unit - 内存管理单元&#xff09;&#xff1a; …

新星计划·第四季·Python赛道报名入口 -〖你就是下一个新星〗

↓↓↓报名方式&#xff1a;&#xff08;下滑到本页面底部&#xff09;重要提醒&#xff1a;这里是新星计划第四季Python赛道报名入口&#xff0c;一经报名&#xff0c;不可更换。报名入口点击此处跳转 一、新星计划 新星计划是一个以发掘潜力新人、培养优质博主为目标的创作…

css3动画属性

边框弧度 border-radius:value // 四角 border-radius:value value // 左上右下 右上左下 border-radius:value value value value // 左上 右上 右下 左下 text-shadow:value value value color; // 水平 垂直 模糊度 颜色 线性渐变&#xff1a;background-image:linear-…