[2023.09.15]: Yew SSR模式下的条件编译问题

昨天才写了Rust的条件编译,没想到这个问题还没完。
昨天我还为它的强大而赞叹不已,自以为对它了解了八九成,然而今天我才猛然意识到,这个里面的深度远超我的想象。我估计,我现在只了解其中的冰山一角吧。

故事从客户端post数据的后端api说起。

习以为常的思维影响着我解决问题的方式,对于这种问题,我通常会寻找一个库来处理后端的 API 交互问题。因此,我在互联网上四处搜寻与 Yew SSR 开发相关的示例,并发现大部分示例都使用了 reqwest 库。但是,当时我并没有注意到一个细节,这些示例都只调用了 get 方法,却没有涉及到 post 方法的应用场景。

Yew官方给出的例子如下:

#[cfg(feature = "ssr")]
async fn fetch_uuid() -> Uuid {// reqwest works for both non-wasm and wasm targets.let resp = reqwest::get("https://httpbin.org/uuid").await.unwrap();let uuid_resp = resp.json::<UuidResponse>().await.unwrap();uuid_resp.uuid
}#[function_component]
fn Content() -> HtmlResult {let uuid = use_prepared_state!((), async move |_| -> Uuid { fetch_uuid().await })?.unwrap();Ok(html! {<div>{"Random UUID: "}{uuid}</div>})
}

因此,我就顺着这个例子给出的reqwest,来解决我要post数据到后端api的问题。

让我们细看一下官方给出的例子代码,fetch_uuid带有条件编译#[cfg(feature="ssr")],也就是说这个函数只会在编译服务器端的target文件时才会编译进去,然后看一下调用fetch_uuid的地方,用的是use_prepared_state!宏,它也会作用于服务器端。连起来理解,就是在服务器端调用fetch_uuid函数来获取数据,并将数据“发送”到客户端。这里的“发送”实际上就是wasm的加载过程,也就是说在服务器端和客户端都可以看到这个值。理解了这段例子代码之后,我们会发现这里的过程都发生在服务器端,而不是客户端。我们要把数据post到后端api,这个场景发生在wasm加载到浏览器之后,由用户在UI上的操作发起的。

显然,这段例子代码没有涉及到我的需求,但是reqwest库中也有post的功能,能不能通过reqwest库来实现我要把前端的数据post到后端api的这个需求呢?

答案是NO。

首先聊一下SSR模式,即服务器端生成,在这个模式中,针对后端api的访问就有两种情况

  1. 在服务器的运行环境中来访问后端api;
  2. 在浏览器端的wasm环境中来访问后端api;
    明白了这两种情况后,我们就很好理解在Cargo.toml中的这段配置了。
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen-futures = "0.4"
wasm-logger = "0.2"
log = "0.4"[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1.29.0", features = ["full"] }
warp = "0.3"
clap = { version = "4", features = ["derive"] }

这个配置,说明wasm-bindgen-futures, wasm-logger, log这3个依赖只有在编译成wasm时才会有效,而tokio, warp, clap这个3个依赖,只有在编译成服务端代码时才会有效。
而reqwest依赖于tokio库,因此reqwest只能用于服务器端的api处理,不能用于浏览器端wasm环境中的api处理。当然,你完全不用担心如果你在开发这类需求时,会不会在这个地方配置出错,完全不用担心这个问题,因为编译器会把问题报给你。这一点总算是给Rust挽回了一点面子。

故事到这里还没有完,彩蛋还在后面。

按照上面的Cargo.toml,我最初在运行cargo clippy时总是报错,说wasm_bindgen_futures::spawn_local不存在,但后来发现运行trunk build index.html时,这个错误又没了,所以我就怀疑上了条件编译这一块。说明在运行trunk build index.html时,它产生的目标是wasm。算了吧,能够完成build也不错,先把流程走通。但是后来再运行cargo run --features=ssr --bin=ssr_server -- --dir dist时,又报wasm_bindgen_futures::spawn_local不存在的错误。我想这里编译的是服务端代码,它的编译目标应该是非wasm的。而wasm-bindgen-futures又是声明在wasm下面,因此找不到wasm_bindgen_futures。所以,我尝试把wasm-bindgen-futures一到[dependencies]下,这下子都不报错了。

因此,我觉得这里应该折射出一个问题,即Yew的SSR开发模式中,没有严格区分哪些代码要被编译成服务器端的target,哪些代码要编译成客户端wasm的target。

当然,最后的结局编译成功,运行时也没有什么问题。

总结一下,在Yew的SSR开发中,虽然代码都在一个项目之内,但是要注意区分代码和功能是哪些运行在服务器环境,哪些运行在浏览器的wasm环境。可以通过指定特定目标架构的依赖项([target.'cfg()'.dependencies]),配合编译器来帮助我们发现错误。

说了这么多,最终的代码如下:
Cargo.toml

reqwest = { version = "0.11.18", features = ["json"] }
gloo-net = { version="0.4.0", features=["json", "http"]}
wasm-bindgen-futures = "0.4"[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-logger = "0.2"
log = "0.4"[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1.29.0", features = ["full"] }
warp = "0.3"

客户端发起post请求的代码:

    let on_save = {Callback::from(move |editorData: EditorData| {spawn_local(async move {if let Ok(req) = Request::post("/notes").json(&editorData) {let _ = req.send().await;} else {log!("invalid json");}})})};

今天的故事就讲到这里,里面有不对的地方,还望大家多多指教。(终于要到后端的开发了)

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

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

相关文章

使用cpolar配合Plex打造个人媒体站,畅享私人影音娱乐空间

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特别是各…

OGAI详解:AIStation调度平台如何实现大模型高效长时间持续训练

大模型是当前通用人工智能产业发展创新的核心技术&#xff0c;目前国内已发布的生成式AI模型超过了100个。面向以大模型为核心的生成式AI开发与应用场景&#xff0c;近日浪潮信息发布了大模型智算软件栈OGAI&#xff08;Open GenAI Infra&#xff09;——“元脑生智”&#xff…

js 不同域iframe 与父页面消息通信

不同域iframe 与父页面消息通信 &#x1f4a1;访问 iframe 页面中的方法&#x1f4a1;跨文本消息监听消息发送消息 var iframe document.getElementById("myIframe"); var iframeWindow iframe.contentWindow;&#x1f4a1;访问 iframe 页面中的方法 iframeWindow…

java基础-集合-ConcurrentHashMap源码学习

文章目录 putValinitTableget putVal final V putVal(K key, V value, boolean onlyIfAbsent) {// 不允许 key或value 为null&#xff0c;HashMap允许 key 为nullif (key null || value null) throw new NullPointerException();// 计算hash&#xff0c;将key的hashCode的高…

Stable Diffusion WebUI内存不够爆CUDA Out of memory怎么办?

在我们运行SD的时候,我们经常会爆CUDA Out of memory。 我们应该怎么办呢? 这是因为我们的显存或者内存不够了。 如果你是用cpu来跑图的则表示内存不够,这个时候就需要换个大点的内存了。 如果你是用gpu来跑图的就说明你显存不够用咯,这时候咋办呢? 下面我将一一述说…

Zookeeper运维

我是一个目录 1. 参数说明2. Zookeeper优化建议3. Zookeeper性能查看4. 建议 1. 参数说明 工作节点瞬间压力大&#xff0c;导致和集群通信出现延迟&#xff0c;被踢出节点&#xff0c;瞬间释放的连接立即又连接到另外节点&#xff0c;最终集群挂掉。加了一些延迟配置后&#xf…

华为云创新中心黑湖科技:将智能制造进行到底

编辑&#xff1a;阿冒 设计&#xff1a;沐由 一如去年&#xff0c;第二届828 B2B企业节从8月28日-9月15日期间&#xff0c;再一次成为广大企业界关注的焦点。 当前&#xff0c;数字技术已经被广泛被融入到产品、服务与流程当中&#xff0c;用以转变客户的业务成果&#xff0c;以…

ChatGPT在职业规划中的智能助手

随着科技的不断发展&#xff0c;人工智能&#xff08;AI&#xff09;正逐渐成为我们日常生活的一部分。ChatGPT作为一种智能语言模型&#xff0c;可以在职业规划中充当智能助手的角色。本文将探讨ChatGPT在职业规划中的应用&#xff0c;以及它如何成为未来工作的智能伙伴。 首先…

基于SpringBoot+Vue实现的党校培训管理系统源代码+数据库

一、简介 项目简介&#xff1a; 基于微服务架构的党校培训管理系统&#xff0c; 完整代码下载地址&#xff1a;党校培训管理系统 大体总结&#xff1a; 前端使用Vue.js框架&#xff0c;UI组件库使用Element UI与Ant Design Vue&#xff0c;后端基于Spring Boot&#xff0c;使…

实现客户端pineline的思路

背景&#xff1a; redis集群不支持客户端的mget操作&#xff0c;但是业务上对这个redis集群的批量操作的需求一直都在&#xff0c;所以有各种客户端实现了各式各样的pineline实现,本文就记录下我们公司的实现方式 pineline实现思路 1.pineline要快 pineline之所以快是因为可…

mybatis mapper.xml 文件外键映射

1.业务背景 最近负责标签管理业务&#xff0c;因为设计打标签功能就需要用到中间表。在之前的写法&#xff0c;将符合的数据先查询出来在应用层做匹配封装。如果是大表关联性复杂考虑到之后的扩展性&#xff0c;这种写法符合要求的&#xff0c;唯一缺点就是让你代码看的很臃肿&…

面试算法6:排序数组中的两个数字之和

题目 输入一个递增排序的数组和一个值k&#xff0c;请问如何在数组中找出两个和为k的数字并返回它们的下标&#xff1f;假设数组中存在且只存在一对符合条件的数字&#xff0c;同时一个数字不能使用两次。例如&#xff0c;输入数组[1&#xff0c;2&#xff0c;4&#xff0c;6&…

【华为重启门】华为/荣耀手机一直自动重启原因解决方案(荣耀V10)

文章目录 【目前&#xff1a;系统回退安卓10、CPU贴了硅胶片。一天没重启了】1.问题描述2.分析原因3.解决方案4.实际操作 【目前&#xff1a;系统回退安卓10、CPU贴了硅胶片。一天没重启了】 1.问题描述 荣耀V10&#xff0c;莫名其妙的、无规律的死机重启。 一开始是重启后进…

Ubuntu22.04配置WiFi

Ubuntu22.04配置WiFi 注意&#xff1a;在/etc/netplan/​下的配置文件&#xff0c;格式一定要正确&#xff0c;否则用sudo netplan try​的时候会报错 一、查看无线网卡的名称 //choice-1 ls /sys/class/net//choice-2 ip a//choice-3 ifconfig -a‍ 二、修改配置文件 文件…

jmeter接口测试及详细步骤以及项目实战教程

在接口测试项目实战中&#xff0c;JMeter是一款非常强大和流行的自动化测试工具&#xff0c;它可以测试各种类型的应用程序&#xff0c;并通过采样和报告来识别性能瓶颈和API的问题。本文将为你提供一个基于实际项目的JMeter接口测试项目实战教程&#xff0c;指导你如何使用JMe…

分布式事务解决方案之2PC

分布式事务解决方案之2PC 前面已经学习了分布式事务的基础理论&#xff0c;以理论为基础&#xff0c;针对不同的分布式场景业界常见的解决方案有2PC、 TCC、可靠消息最终一致性、最大努力通知这几种。 什么是2PC 2PC即两阶段提交协议&#xff0c;是将整个事务流程分为两个阶段…

一种新的图像去噪方式:图像修补+斑点检测的预处理

灵感来源于我之前写的一篇博客&#xff1a;图像处理&#xff1a;基于cv2.inpaint()图像修补。 这种方式可以有效的去除白色的噪点&#xff0c;这里我们需要一张噪点的图像&#xff0c;你可以用下面的代码随机生成一张噪点图片&#xff1a; import cv2 import numpy as np # i…

软件设计模式系列之六——单例模式

1 模式的定义 单例模式&#xff08;Singleton Pattern&#xff09;是一种常见的创建型设计模式&#xff0c;其主要目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取该实例。这意味着无论何时何地&#xff0c;只要需要该类的实例&#xff0c;都会返回同一个…

二刷力扣--栈和队列

栈和队列 栈和队列基础&#xff08;Python&#xff09; 栈一种先进后出&#xff0c;队列先进后出。 Python中可以用list实现栈&#xff0c;用append()模拟入栈&#xff0c;用pop()模拟出栈。 也可以用list实现队列&#xff0c;但是效率较低&#xff0c;一般用collections.deq…

vue2以ElementUI为例构建notify便捷精美提示

我们先引入一个 第三方UI库 这里 我们以elementUI为例 先引入依赖 npm install element-ui --save然后 在 main.js 入口文件中 引入一下 import ElementUI from element-ui import element-ui/lib/theme-chalk/index.cssVue.use(ElementUI)然后 在组件中使用 this.$notify({…