在vue中如何书写 SSR 友好的代码
文章目录
- 前言
- 服务端的响应性
- 组件生命周期钩子
- 访问平台特有 API
- 跨请求状态污染
- 激活不匹配
- 自定义指令
- teleports
- 后言
前言
hello world欢迎来到前端的新世界
😜当前文章系列专栏:vue.js
🐱👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出现错误,感谢大家指出)🌹
💖感谢大家支持!您的观看就是作者创作的动力
服务端的响应性
在 SSR 期间,每一个请求 URL 都会映射到我们应用中的一个期望状态。因为没有用户交互和 DOM 更新,所以响应性在服务端是不必要的。为了更好的性能,默认情况下响应性在 SSR 期间是禁用的。
组件生命周期钩子
因为没有任何动态更新,所以像 onMounted
或者 onUpdated
这样的生命周期钩子不会在 SSR 期间被调用,而只会在客户端运行。
你应该避免在 setup() 或者 <script setup>
的根作用域中使用会产生副作用且需要被清理的代码。这类副作用的常见例子是使用 setInterval 设置定时器。我们可能会在客户端特有的代码中设置定时器,然后在 onBeforeUnmount
或 onUnmounted
中清除。然而,由于 unmount 钩子不会在 SSR 期间被调用,所以定时器会永远存在。为了避免这种情况,请将含有副作用的代码放到 onMounted
中。
访问平台特有 API
通用代码不能访问平台特有的 API,如果你的代码直接使用了浏览器特有的全局变量,比如 window 或 document,他们会在 Node.js 运行时报错,反过来也一样。
对于在服务器和客户端之间共享,但使用了不同的平台 API 的任务,建议将平台特定的实现封装在一个通用的 API 中,或者使用能为你做这件事的库。例如你可以使用 node-fetch 在服务端和客户端使用相同的 fetch API。
对于浏览器特有的 API,通常的方法是在仅客户端特有的生命周期钩子中惰性地访问它们,例如 onMounted
。
请注意,如果一个第三方库编写时没有考虑到通用性,那么要将它集成到一个 SSR
应用中可能会很棘手。你或许可以通过模拟一些全局变量来让它工作,但这只是一种 hack
手段并且可能会影响到其他库的环境检测代码。
跨请求状态污染
在状态管理一章中,我们介绍了一种使用响应式 API 的简单状态管理模式。而在 SSR 环境中,这种模式需要一些额外的调整。
上述模式在一个JavaScript
模块的根作用域中声明共享的状态。这是一种单例模式——即在应用的整个生命周期中只有一个响应式对象的实例。这在纯客户端的 Vue 应用中是可以的,因为对于浏览器的每一个页面访问,应用模块都会重新初始化。
然而,在 SSR 环境下,应用模块通常只在服务器启动时初始化一次。同一个应用模块会在多个服务器请求之间被复用,而我们的单例状态对象也一样。如果我们用单个用户特定的数据对共享的单例状态进行修改,那么这个状态可能会意外地泄露给另一个用户的请求。我们把这种情况称为跨请求状态污染。
从技术上讲,我们可以在每个请求上重新初始化所有 JavaScript 模块,就像我们在浏览器中所做的那样。但是,初始化 JavaScript 模块的成本可能很高,因此这会显著影响服务器性能。
推荐的解决方案是在每个请求中为整个应用创建一个全新的实例,包括 router
和全局 store
。然后,我们使用应用层级的 provide
方法来提供共享状态,并将其注入到需要它的组件中,而不是直接在组件中将其导入:
// app.js (在服务端和客户端间共享)
import { createSSRApp } from 'vue'
import { createStore } from './store.js'// 每次请求时调用
export function createApp() {const app = createSSRApp(/* ... */)// 对每个请求都创建新的 store 实例const store = createStore(/* ... */)// 提供应用级别的 storeapp.provide('store', store)// 也为激活过程暴露出 storereturn { app, store }
}
激活不匹配
如果预渲染的 HTML 的 DOM 结构不符合客户端应用的期望,就会出现激活不匹配。最常见的激活不匹配是以下几种原因导致的:
- 组件模板中存在不符合规范的 HTML 结构,渲染后的 HTML 被浏览器原生的
HTML
解析行为纠正导致不匹配。举例来说,一个常见的错误是不能被放在中:
<p><div>hi</div></p>
如果我们在服务器渲染的 HTML 中出现这样的代码,当遇到
,并解析为以下 DOM 结构:
<p></p>
<div>hi</div>
<p></p>
-
渲染所用的数据中包含随机生成的值。由于同一个应用会在服务端和客户端执行两次,每次执行生成的随机数都不能保证相同。避免随机数不匹配有两种选择:
-
利用 v-if + onMounted 让需要用到随机数的模板只在客户端渲染。你所用的上层框架可能也会提供简化这个用例的内置 API,比如 VitePress 的 组件。
-
使用一个能够接受随机种子的随机数生成库,并确保服务端和客户端使用同样的随机数种子 (比如把种子包含在序列化的状态中,然后在客户端取回)。
-
-
服务端和客户端的时区不一致。有时候我们可能会想要把一个时间转换为用户的当地时间,但在服务端的时区跟用户的时区可能并不一致,我们也并不能可靠的在服务端预先知道用户的时区。这种情况下,当地时间的转换也应该作为纯客户端逻辑去执行。
当 Vue 遇到激活不匹配时,它将尝试自动恢复并调整预渲染的 DOM 以匹配客户端的状态。这将导致一些渲染性能的损失,因为需要丢弃不匹配的节点并渲染新的节点,但大多数情况下,应用应该会如预期一样继续工作。尽管如此,最好还是在开发过程中发现并避免激活不匹配。
自定义指令
因为大多数的自定义指令都包含了对 DOM 的直接操作,所以它们会在 SSR 时被忽略。但如果你想要自己控制一个自定义指令在 SSR 时应该如何被渲染 (即应该在渲染的元素上添加哪些 attribute
),你可以使用 getSSRProps
指令钩子:
const myDirective = {mounted(el, binding) {// 客户端实现:// 直接更新 DOMel.id = binding.value},getSSRProps(binding) {// 服务端实现:// 返回需要渲染的 prop// getSSRProps 只接收一个 binding 参数return {id: binding.value}}
}
teleports
在 SSR 的过程中 Teleport 需要特殊处理。如果渲染的应用包含 Teleport
,那么其传送的内容将不会包含在主应用渲染出的字符串中。在大多数情况下,更推荐的方案是在客户端挂载时条件式地渲染 Teleport
。
如果你需要激活 Teleport
内容,它们会暴露在服务端渲染上下文对象的 teleports
属性下:
const ctx = {}
const html = await renderToString(app, ctx)console.log(ctx.teleports) // { '#teleported': 'teleported content' }
跟主应用的 HTML 一样,你需要自己将 Teleport
对应的 HTML 嵌入到最终页面上的正确位置处。
后言
创作不易,要是本文章对广大读者有那么一点点帮助 不妨三连支持一下,您的鼓励就是博主创作的动力
相关文章:
在vue中如何书写 SSR 友好的代码
文章目录 前言服务端的响应性组件生命周期钩子访问平台特有 API跨请求状态污染激活不匹配自定义指令teleports后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏:vue.js 🐱👓博主在前端领域还有很多…...
开源与闭源:数字时代大模型之辩
欢迎大家到我的博客浏览更多文章。YinKais Blog | YinKais Blog 大模型的未来:开源与闭源的博弈 在大模型的发展中,开源和闭源两种截然不同的开发模式发挥着重要的作用。开源以其技术共享的特性,吸引了大量人才参与,推动了大模型的…...

卷积神经网络(VGG-16)猫狗识别
文章目录 一、前言二、前期工作1. 设置GPU(如果使用的是CPU可以忽略这步)2. 导入数据3. 查看数据 二、数据预处理1. 加载数据2. 再次检查数据3. 配置数据集4. 可视化数据 三、构建VG-16网络四、编译五、训练模型六、模型评估七、保存and加载模型八、预测…...

Mysql 行转列,把逗号分隔的字段拆分成多行
目录 效果如下源数据变更后的数据 方法第一种示例SQL和业务结合在一起使用 第二种示例SQL和业务结合在一起使用 结论 效果如下 源数据 变更后的数据 方法 第一种 先执行下面的SQL,看不看能不能执行,如果有结果,代表数据库版本是可以的&…...

基于单片机设计的智能水泵控制器
一、前言 在一些场景中,如水池、水箱等水体容器的管理中,保持水位的稳定是至关重要的。传统上,人们通常需要手动监测水位并进行水泵的启停控制,这种方式不仅效率低下,还可能导致水位过高或过低,从而对水体…...

反转链表的实现
题目描述: 给出一个链表的头节点,将其反转,并返回新的头节点 思路1:反转地址 将每个节点里的地址由指向下一个节点变为指向前一个节点 定义三个结构体指针n1,n2,n3,n1表示改后指针的地址,n2表示要修改结构体里next的…...

python之pyqt专栏6-信号与槽2
上一篇python之pyqt专栏5-信号与槽1-CSDN博客,我们通过信号与槽实现了点击Button,改变Label的文本内容。可以知道 信号是在类中定义的,是类的属性 槽函数是信号通过connect连接的任意成员函数,当信号发生时,执行与信号…...
C语言中一些特殊字符的输出
目录 %的介绍 斜杠与反斜杠 转义字符 %的介绍 int a1; 1、printf(’’%d’’,a);//输出1 2、printf(’’%%d’’,a);//输出%d 3、printf(’’%%%d ‘’,a)//输出%1 C语言中,%也是转义符,%%相当于% 斜杠与反斜杠 首先需要明白…...

Opencv制作电子签名(涉及知识点:像素过滤,图片通用resize函数,像素大于某个阈值则赋值为其它的像素值)
import cv2def resize_by_ratio(image, widthNone, heightNone, intercv2.INTER_AREA):img_new_size None(h, w) image.shape[:2] # 获得高度和宽度if width is None and height is None: # 如果输入的宽度和高度都为空return image # 直接返回原图if width is None:h_ratio …...

【漏洞复现】大华智慧园区综合管理平台deleteFtp接口远程命令执行
漏洞描述 大华智慧园区综合管理平台deleteFtp接口存在远程命令执行,攻击者可利用该漏洞执行任意命令,获取服务器控制权限。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益…...

Unity Image - 镜像
1、为什么要使用镜像 在游戏开发过程中,我们经常会为了节省 美术图片资源大小,美术会将两边相同的图片进行切一半来处理。如下所示一个按钮 需要 400 * 236,然而美术只需要切一张 74*236的大小就可以了。这样一来图集就可以容纳更多的图片。…...

深入Spring Security魔幻山谷-获取认证机制核心原理讲解(新版)
文/朱季谦 这是一个古老的传说。 在神秘的Web系统世界里,有一座名为Spring Security的山谷,它高耸入云,蔓延千里,鸟飞不过,兽攀不了。这座山谷只有一条逼仄的道路可通。然而,若要通过这条道路前往另一头的…...

【知网稳定检索】第九届社会科学与经济发展国际学术会议 (ICSSED 2024)
第九届社会科学与经济发展国际学术会议 (ICSSED 2024) 2024 9th International Conference on Social Sciences and Economic Development 第九届社会科学与经济发展国际学术会议(ICSSED 2024)定于2024年3月22-24日在中国北京隆重举行。会议主要围绕社会科学与经济发展等研究…...
使用Spark写入数据到数据库表
项目场景: 使用Spark写入数据到数据库表 问题描述 Column "20231201" not found in schema Some(StructType(StructField(sdate,IntegerType,false),StructField(date_time,StringType,true),StructField(num,LongType,false),StructField(table_code,S…...

Codebeamer—软件全生命周期管理轻量级平台
产品概述 Codebeamer涵盖了软件研发的生命周期,在一个整合的平台内支持需求管理、测试管理、软件开发过程管理以及项目管理等,同时具有IToperations&DevOps相关的内容,并支持变体管理的功能。对于使用集成的应用程序生命周期管理…...
Yocto - bb脚本中使用的SRC_URI、SRCREV和S
我们遇到的各种自己不了解的技术或产品时,都需要阅读用户手册。用户手册里的内容很多时,除了由目录组织文档结构外,通常还有有一个词汇表,一般作为附录放在文档最后。 通过这个按照字母排序的词汇表,可以在对整个文档还…...

LeetCode | 965. 单值二叉树
LeetCode | 965. 单值二叉树 OJ链接 首先判断树为不为空,为空直接true然后判断左子树的val,和根的val相不相同再判断右子树的val,和根的val相不相同最后递归左子树和右子树 bool isUnivalTree(struct TreeNode* root) {if(root NULL)retur…...

YOLOv8创新魔改教程(一)如何进行模块创新
YOLOv8创新魔改教程(一)如何进行模块创新 YOLOv8创新魔改教程 本人研一,最近好多朋友问我要如何修改模型创新模块,就想着不如直接开个专栏歇一歇文章,也算是对自己学习的总结,本专栏以YOLOv8为例…...

postgresql-shared_buffers参数详解
shared_buffers 是 PostgreSQL 中一个非常关键的参数,用于配置服务器使用的共享内存缓冲区的大小。这些缓冲区用于存储数据页,以便数据库可以更快地访问磁盘上的数据。 这个参数在 PostgreSQL 的性能方面有着重要的影响。增加 shared_buffers 可以提高数…...

windows10 Arcgis pro3.0-3.1
我先安装的arcgis pro3.0,然后下载的3.1。 3.0里面有pro、help、sdk、还有一些补丁包根据个人情况安装。 3.1里面也是这些。 下载 正版试用最新的 ArcGIS Pro 21 天教程,仅需五步!-地理信息云 (giscloud.com.cn) 1、安装windowsdesktop-…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...