rust 前端npm依赖工具rsup升级日志
rsup
是使用 rust 编写的一个前端 npm 依赖包管理工具,可以获取到项目中依赖包的最新版本信息,并通过 web 服务的形式提供查看、升级操作等一一系列操作。
在前一篇文章中,记录初始的功能设计,自己的想法实现过程。在自己的使用过程功能中,也会发现一些存在的问题,有一些问题值得记录的再次标记,供大家参考。
rsup 工具安装
在上一篇文章中描写的安装rsup
工具部分错误,因为我本地是 macos 系统,
rust 默认执行cargo build
构建的是适合 macos 的可执行文件,对于 windows、linux 是不能直接用;还有一个问题,就是rsup-web
静态服务资源是不会被编译进工具包的,我本地能用也仅仅是我本地有源代码,它指向静态资源路径的就是我电脑的绝对地址。
可以采取将静态资源链接打包进二进制文件中。
- 使用
include_bytes!
rust 内置的宏将静态文件的内容嵌入到二进制文件 - 使用第三方 crate,比如
embed-resource
或者rust-embed
但是为了方便控制 web 静态资源,比如可以单独更新。采取了静态文件和可执行文件分离的方式,提供下载器同时下载rsup
可执行文件和rsup-web
web 静态资源。针对不同的系统定义默认的下载路径,然后通过配置文件读取 web 静态资源提供 web 服务。
rsup
工具包包含了配置文件、可执行文件、web 服务文件等。根据不同的系统,提供了三种安装工具包包括 linux、macos、windows。
macos installer
ubuntu instanller
windows instanller
提供了安装脚本文件sh
一键下载解压、安装。无需手动配置环境变量。
curl -fsSL https://github.com/ngd-b/rsup/blob/main/install.sh | sh
windows
用户需要手动下载安装包,解压后执行installer.exe
即可,并且需要手动配置环境变量。
installer
子包下载资源
这是为了解决上述问题新增的一个安装器,更友好的交互方式进行安装。也方便后面对下载方式进行更友好的优化。
执行安装器需要使用管理员权限。windows
右键以管理员身份执行 exe;类 linux 系统需要使用sudo
执行。
提供了从 github 或者 gitee 下载资源两种方式。使用第三方库 crate 目前只提供了从dialoguer
进行交互选择。github
下载资源。
use clap::{Parser, ValueEnum};
use dialoguer::{theme::ColorfulTheme, Select};#[derive(Parser, Debug, Clone, ValueEnum)]
pub enum Origin {Github,Gitee,
}impl Origin {// ...pub fn as_str(&self) -> &'static str {match self {Origin::Github => "github",Origin::Gitee => "gitee",}}/// 将枚举pub fn choices() -> Vec<&'static str> {vec![Origin::Github.as_str(), Origin::Gitee.as_str()]}
}/// 提示用户选择下载源
/// @return 下载源
pub fn prompt_origin() -> Origin {let select = Select::with_theme(&ColorfulTheme::default()).with_prompt("Please select download source...").default(0).items(Origin::choices().as_slice()).interact().unwrap();match select {0 => Origin::Github,1 => Origin::Gitee,_ => unreachable!(),}
}
使用reqwest
下载资源,并将资源保存到默认路径。文件路径output
的目录必须要提前创建,而fs::File::create(output)
创建了资源文件,如果文件已经存在会直接覆盖。
use reqwest::Client;
use tokio::fs;/// 下载文件
///
async fn download_file(client: &Client, url: &str, output: &str) -> Result<(), Box<dyn Error>> {// 下载地址let res = client.get(url).send().await?;if res.status().is_success() {// 下载成功// 保存文件到指定目录// 文件路径let mut file = fs::File::create(output).await?;// 保存文件let bytes = res.bytes().await?;file.write_all(&bytes).await?;Ok(())} else {let error_message = format!("Request failed with status code: {}", res.status());Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other,error_message,)))}
}
文件下载完成后需要解压。所有的资源文件都是.tar.gz
格式的,使用flate2
解压文件,并且需要使用tar
进行解包提取到指定目录。
use flate2::read::GzDecoder;
use tar::Archive;/// 解压文件
///
/// @param url 下载地址
/// @param target_dir 保存目录
async fn decompress_file(url: &str, target_dir: &str) -> Result<(), Box<dyn Error>> {let tar_gz = File::open(url)?;let decomppress = GzDecoder::new(tar_gz);let mut archive = Archive::new(decomppress);// 处理解压目录,不存在则创建目录if !Path::new(target_dir).exists() {fs::create_dir_all(target_dir).await?;}archive.unpack(target_dir)?;Ok(())
}
所需要的资源下载解压完成后,现在默认目录下(类 linux 系统下是/opt/rsup
)有三个文件
rsup
可执行文件config.toml
配置文件web
web 静态资源
可以直接去执行rsup
可执行文件。但是当前目录下没有package.json
文件,我们可以指定参数--dir
去访问指定目录下的package.json
。为了方便命令的使用,安装时经将命令添加到环境变量中。
针对不同的操作系统,环境变量的配置文件不一样。windows
系统需要用户自行配置,macos
系统下是.zshrc
;其他类系统默认为.bashrc
use std::io::Write;
use std::{error::Error, fs::OpenOptions};/// 提示用户是否添加命令到环境变量
/// 默认添加
pub fn prompt_add_to_env(path: &str) -> Result<(), Box<dyn Error>> {// ... 省略部分代码let home_dir = std::env::var("HOME")?;// 确定系统使用的shelllet shell_file_name = match os {"macos" => ".zshrc",_ => ".bashrc",};// 环境变量配置目录let shell_config_path = format!("{}/{}", home_dir, shell_file_name);// 写入配置let mut file = OpenOptions::new().append(true).open(shell_config_path)?;writeln!(file, "\n# Add rsup to PATH\nexport PATH=\"{}:$PATH\"", path)?;
}
写入配置文件后,需要重新加载配置文件。执行source ~/.zshrc
或者.bashrc
,这样就可以全局使用rsup
命令了。
config
子包管理配置文件
配置文件的读取和写入使用config
子包,提供配置文件读写操作。installer
安装时会默认生成配置文件,在rsup
执行时会读取配置文件。为了方便配置文件管理,新增config
子包。
使用了 crate toml
对配置文件config.toml
进行读写序列化和反序列化。
use std::{error::Error,fs::{self, File},io::{self, Write},path::Path,
};impl Config {/// 读取配置文件///pub async fn read_config() -> Result<(), Box<dyn Error>> {// 读取配置文件let config_dir = Config::get_url();let config_file_dir = format!("{}/config.toml", config_dir);// ... 省略部分代码let config_content = fs::read_to_string(&config_file_dir)?;let config: Config = toml::from_str(&config_content)?;Ok(())}/// 写入配置文件pub async fn write_config() -> Result<Config, Box<dyn Error>> {let config_dir = Config::get_url();// ... 省略部分代码// 配置文件let config_url = format!("{}/config.toml", config_dir);let mut file = File::create(config_url.clone())?;let mut config = Config::default();// 配置文件路径config.dir = config_dir.clone();// 静态文件目录config.web.static_dir = format!("{}/web", &config_dir);let config_content = toml::to_string(&config)?;file.write_all(config_content.as_bytes())?;Ok(config)}
}
在主入口main
中执行读取配置文件,然后可以在各个子包中读取。为了方便使用,在config
中提供了静态全局变量CONFIG
,使用了第三方 crateonce_cell
实现。
use once_cell::sync::OnceCell;// 全局共享配置
pub static CONFIG: OnceCell<Config> = OnceCell::new();impl Config {pub async fn read_config() -> Result<(), Box<dyn Error>> {// ... 省略部分代码// 保存配置数据共享CONFIG.set(config).unwrap();}/// 父级包获取配置pub fn get_config() -> &'static Config {CONFIG.get().unwrap()}
}
这样就可以在其他子包中直接使用config::Config::get_config()
获取配置数据了。
配置文件中包含的配置项有:
name = "rsup"
version = "0.3.0"
dir = "/opt/rsup"[web]
port = 8888
static_dir = "/opt/rsup/web"[pkg]
npm_registry = "https://registry.npmmirror.com"
配置文件中的dir
字段是安装目录,默认安装在/opt/rsup
;web.port
字段是 web 服务的端口号,默认8888;pkg.npm_registry
字段是 npm 依赖源地址,默认为国内镜像。通常只建议修改pkg.npm_registry
设置源地址,方便请求依赖包。
command
子包提供命令行交互
提供了新的子包command
,用于解析命令行参数。统一管理命令行参数,方便使用。并且提供了一些方法使用。
在使用rsup
命令时,可以指定目录使用前端 npm 依赖管理web服务;也可以通过输入自命令进行交互式操作。
子命令包含了两部分:Config
配置命令;Update
更新命令。新创建了command
子包,在主包解析参数时进行逻辑判断,如果输入命令则执行对应的子命令;未输入子命令则默认执行 web 服务;
#[tokio::main]
async fn main() {let args = Cli::parse();match args.command {Some(Commands::Config { .. }) | Some(Commands::Update { .. }) => {run().await;}_ => {let package = Package::new();// 默认启动pkg解析服务let package_clone = package.clone();task::spawn(async move {pkg::run(args.pkg_args, package_clone).await;});web::run(package.clone()).await;}}
}
执行run()
方法调用了子包command
中的方法,并解析命令行参数,根据参数执行对应的操作。
pub async fn run() {let cli = Commands::parse();let _ = match cli {Commands::Config { config } => match config {ConfigOptions::List => ConfigOptions::list_config().await,ConfigOptions::Set { key, value } => ConfigOptions::set_config_value(&key, value).await,ConfigOptions::Get { key } => ConfigOptions::get_config_value(&key).await,ConfigOptions::Delete => todo!(),},Commands::Update { update } => {// 获取最新的包地址let (rsup_url, rsup_web_url) = utils::get_pkg_url(None);// 获取命令安装目录let config = external_config::Config::get_config().await;match update {UpdateOptions::Rsup => UpdateOptions::rsup_update(rsup_url, &config.dir).await,UpdateOptions::Web => {UpdateOptions::rsup_web_update(rsup_web_url, &config.dir).await}}}};
}
Config
配置命令
Config
配置命令用来管理配置文件,提供交互式操作。我们之前在installer
安装时,默认生成配置文件。通过config
命令可以查看、修改、删除配置项。
config list
可以展示出配置文件config.toml
,在我们安装好rsup
命令后,执行rsup config list
可以看到配置文件内容。
config set key value
可以修改配置文件中的值,例如:rsup config set web.port 9999
修改web服务端口号。
对于配置文件的访问、修改,主要是使用了子包config
中的方法。为了方便修改,对于子包config
的实现进行了调整,文章上面提到的实现为第一版实现,可以做对比差异。
初始实现的需要在core
主入口中调用一次读取配置文件,然后在其他子包中通过config::Config::get_config()
获取。这种方式在config
子包中不方便直接修改配置文件,需要重新读取。
使用tokio::sync::RwLock
实现读写锁,它是线程安全的。使用once_cell::sync::Lazy
实现懒加载,在首次使用时才去读取配置文件。
pub static CONFIG: Lazy<RwLock<Config>> = Lazy::new(|| {// 这里调用初始化let config = Config::read_config().unwrap();RwLock::new(config)
});
在使用set
设置配置项时,需要管理员权限,配置更新后会同步更新config.toml
配置文件
Update
更新命令
rsup
工具包含自身和web
服务两部分,提供了更新命令,可以更新rsup
工具和web
服务。
通过rsup update rsup
更新工具,通过rsup update web
更新web服务。
utils
子包提供公共方法
为了方便子包之间的共用方法的服用,提供了utils
子包,提供了一些公共方法。
遇到的问题
记录一下遇到的问题,方便后续查阅。
在使用本地config
模块与配置文件config
发生命名冲突
通过extern
明确导入外部模块
// 引入外部crate
extern crate config as external_config;
发布包到crates-io
时名称重复,本地引用修改名称
本地开发时使用的名称utils
,为了发布到crates-io
时,需要修改名称rsup_utils
,避免名称重复。然后本地引用时使用package
字段指定名称,这样不需要去调整代码里的引用。
[package]
utils = { version = "0.1.0", path = "../utils", package = "rsup_utils" }
下载文件时展示进度条
之前的文件下载时,控制台会陷入长时间的阻塞状态,没有任何反应,为了提供更好的交互体验,使用indicatif
展示进度条。
要采用进度条,在下载文件时就要使用流式读取文件,以便更新进度条。
增加两个新的lib库,futures-util
提供对于stream
的扩展函数。
cargo add indicatif
cargo add futures-util
修改请求reqwest
增加特性支持stream
[dependencies]
reqwest = { version = "0.12.9", features = ["stream"] }
修改之前的下载函数download_file
,不再使用write_all
一次性写入文件,通过分批次读取写入,并同步更新进度条。
/// 下载文件
///
async fn download_file(client: &Client, url: &str, output: &str) -> Result<(), Box<dyn Error>> {// 下载地址let res = client.get(url).send().await?;if res.status().is_success() {// 获取文件大小let content_size = res.content_length().ok_or("无法获取文件大小")?;// 下载成功// 保存文件到指定目录// 文件路径let mut file = fs::File::create(output).await?;// 创建进度条let pb = ProgressBar::new(content_size);pb.set_style(ProgressStyle::default_bar().template("{msg} [{elapsed_precise}] {bar:80} {percent}%")?.progress_chars("##-"),);// 创建流式响应体let mut downloaded = 0;let mut stream = res.bytes_stream();while let Some(item) = stream.next().await {let chunk = item?;file.write_all(&chunk).await?;let len = chunk.len() as u64;downloaded += len;pb.set_position(downloaded);}pb.finish_with_message("下载完成");// 保存文件// let bytes = res.bytes().await?;// file.write_all(&bytes).await?;Ok(())} else {let error_message = format!("Request failed with status code: {}", res.status());Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other,error_message,)))}
}
解决web
服务自动后刷新页面加载不到的问题
这是典型的SPA的问题,由于我们使用的是history路由模式,路由由前端控制。我们刷新页面比如http://localhost:8888/home
时,会请求http://localhost:8888/home
,但是web
服务没有这个路由,所以会返回404
,导致刷新页面加载不到。
为了处理这个问题,需要增加通配符路由处理跳转route("/{tail:.*}", web::get().to(index))
,{tail:.*}
是一个路径参数,它可以匹配任何路径。
let server = HttpServer::new(move || {//...App::new().app_data(web::Data::new(ms.clone())).route("/", web::get().to(index)).wrap(cors).service(web::scope("/api").configure(api::api_config)).service(Files::new("/static", format!("{}/static/", &static_file_path)).prefer_utf8(true),).route("/ws", web::get().to(socket_index))// SPA fallback route.route("/{tail:.*}", web::get().to(index))
})
windos
系统下不同的命令执行名称
在windows
系统下,我们执行npm -v
时,实际内部执行的是npm.cmd -v
,而在mac系统下,执行npm -v
时,实际内部执行的是npm -v
,所以需要根据系统类型,使用不同的命令。
// 判断系统,如果是windows,则使用npm.cmd
let npm_cmd = if cfg!(windows) { "npm.cmd" } else { "npm" };
如果安装时是.exe
的话就不需要添加后缀了,直接使用即可。比如node
web
服务API参数映射处理
在处理API请求参数时,通过枚举定义了参数类型,然后通过解析匹配到指定的数据结构。
async fn update_pkg(req: web::Json<ReqParams>,data: web::Data<Ms>,
) -> Result<impl Responder, Error> {match &*req {ReqParams::UpdatePkg(params) => {}err => {// ...}
}
如果定义的数据结构字段存在重叠,某个结构完全包含另一个结构的字段,在匹配时就需要将完全包含的结构放在前面,否则可能会匹配到错误的结构。
#[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)]
pub enum ReqParams {UpdatePkg(UpdateParams),// 删除// 目前接受一个nameRemovePkg(RemoveParams),
}
UpdateParams
和RemoveParams
存在字段重叠,UpdateParams
包含了RemoveParams
的所有字段,要想匹配到UpdateParams
,需要将RemoveParams
放在前面。
最后
部署了rsup
文档服务网站rsup|Npm Helper
往期rsup
文章:
- 模式匹配、trait 特征行为、必包、宏
- 多线程任务执行
- 并发线程间的数据共享
- 包、模块,引用路径
- 开发一个命令行工具
- rust 命令行工具rsup管理前端npm依赖
相关文章:

rust 前端npm依赖工具rsup升级日志
rsup是使用 rust 编写的一个前端 npm 依赖包管理工具,可以获取到项目中依赖包的最新版本信息,并通过 web 服务的形式提供查看、升级操作等一一系列操作。 在前一篇文章中,记录初始的功能设计,自己的想法实现过程。在自己的使用过…...
2.2 STM32F103C8T6最小系统板的四种有关固件的开发方式
2.2.1 四种有关固件的开发方式 四种有关于固件的开发方式从时间线由远及近分别是:寄存器开发、标准外设驱动库开发、硬件抽象层库开发、底层库开发。 四种开发方式各有优缺点,可以参考ST官方的测试与说明。 1.寄存器开发 寄存器编程对于从51等等芯片过渡…...

【C++】 stack和queue以及模拟实现
一、stack及其模拟实现 1.1 stack介绍 stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行 元素的插入与提取操作。stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器&am…...
python与C系列语言的差异总结(2)
Python有很多表达布尔值的方式,布尔常量False、0、Python零值None、空值(如空的列表[]和空字符串""),都被视为False。布尔常量True和其他一切值都被视为True。但不相等。这个自由度相比C类语言更加高。 if (not None):…...

Linux之文件系统
1.前言 文件 内容属性 文件分为被打开的文件(跟基础IO有关,在内存上)和没有被打开的文件(在磁盘上)。 在磁盘上找没有被打开的文件属于文件系统的工作 2.对硬件的理解 2.1 磁盘,服务器,机柜,机房 1.磁…...
LeetCode刷题 -- 23. 合并 K 个升序链表
小根堆排序与合并 K 个有序链表的实现 1. 介绍 本技术文档详细介绍了如何使用 小根堆(Min Heap) 实现 K 个有序链表的合并。 核心思想是: 使用 小根堆 维护当前最小的节点。每次取出堆顶元素(最小值)加入合并链表&…...
DeepSeek在MATLAB上的部署与应用
在科技飞速发展的当下,人工智能与编程语言的融合不断拓展着创新边界。DeepSeek作为一款备受瞩目的大语言模型,其在自然语言处理领域展现出强大的能力。而MATLAB,作为科学计算和工程领域广泛应用的专业软件,拥有丰富的工具包和高效…...

mapbox基础,使用geojson加载fill-extrusion三维填充图层
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️fill-extrusion三维填充图层样式二、�…...

基于 SpringBoot 的 “电影交流平台小程序” 系统的设计与实现
大家好,今天要和大家聊的是一款基于 SpringBoot 的 “电影交流平台小程序” 系统的设计与实现。项目源码以及部署相关事宜请联系我,文末附上联系方式。 项目简介 基于 SpringBoot 的 “电影交流平台小程序” 系统设计与实现的主要使用者分为 管理员 和…...
单片机裸机编程-时机管理
对于 RTOS 实时操作系统,我们是通过 TASK(任务)进行底层操作的,这与裸机编程中的函数(fun)类似。不同的任务或函数实现不同的功能,在RTOS中,单片机有信号量、队列等不同任务之间的通…...
Flutter系列教程之(2)——Dart语言快速入门
目录 1.变量与类型 1.1 num类型 1.2 String类型 1.3 Object与Dynamic 1.4 类型判断/转换 1.5 变量和常量 2.方法/函数 3.类、接口、抽象类 3.1 类 3.2 接口 4.集合 4.1 List 4.2 Set 4.3 Map 5.总结 Dart语言的语法和Kotlin、Java有类似之处,这里就通…...

pyecharts介绍
文章目录 介绍安装pyecharts基本使用全局配置选项 折线图相关配置地图模块使用柱状图使用 介绍 echarts虑是个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可,而Pyhon是门富有表达力的语言&a…...

前缀和相关题目记录(未完待续...)
1 前缀和 一维前缀和是指对于一个数组 a a a,我们定义一个新的数组 s s s,其中每个元素 s [ i ] s[i] s[i] 表示从数组开头到第 i i i 个元素的累加和: s [ i ] a [ 1 ] a [ 2 ] ⋯ a [ i ] ∑ j 1 i a [ j ] s[i] a[1] a[2] \…...

Https解决了Http的哪些问题
部分内容来源:小林coding 详细解析 Http的风险 HTTP 由于是明文传输,所以安全上存在以下三个风险: 1.窃听风险 比如通信链路上可以获取通信内容,用户号容易没。 2.篡改风险 比如强制植入垃圾广告,视觉污染&#…...

OpenCV给图像添加噪声
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 如果你已经有了一张干净的图像,并希望通过编程方式向其添加噪声,可以使用 OpenCV 来实现这一点。以下是一个简单的例子&a…...

湖北中医药大学谱度众合(武汉)生命科技有限公司研究生工作站揭牌
2025年2月11日,湖北中医药大学&谱度众合(武汉)生命科技有限公司研究生工作站揭牌仪式在武汉生物技术研究院一楼101会议室举行,湖北中医药大学研究生院院长刘娅教授、基础医学院院长孔明望教授、基础医学院赵敏教授、基础医学院…...

欢乐力扣:快乐数
文章目录 1、题目描述2、思路1代码 1、题目描述 快乐数。 编写一个算法来判断一个数 n 是不是快乐数。 快乐数定义为:对于一个正整数,每次不断将其转化成 每位数字的平方和。 判断是否最终和会为1,是1就是快乐数,否则不是。 …...

【聊天室后端服务器开发】功能设计-框架与微服务
服务器功能设计 微服务思想应用 微服务架构 主要组成分析 客户端 客户端通过 HTTP 协议与网关进行交互,进行操作如用户注册、好友申请等客户端只需要知道网关的地址,无需关心后端服务的具体实现 网关 作为系统的统一入口,网关负责接收客…...

国标28181协议在智联视频超融合平台中的接入方法
一. 国标28181介绍 国标 28181 协议全称是《安全防范视频监控联网系统信息传输、交换、控制技术要求》,是国内视频行业最重要的国家标准,目前有三个版本: 2011 年:推出 GB/T 28181-2011 版本,为安防行业的前端设备、平…...
让网页“浪“起来:打造会呼吸的波浪背景
每次打开那些让人眼前一亮的网页时,你是否有注意到那些看似随波逐流的动态背景?今天咱们不聊高深的技术,就用最朴素的CSS,来解锁这个让页面瞬间鲜活的秘籍。无需JavaScript,不用复杂框架,准备好一杯咖啡&am…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...

Tauri2学习笔记
教程地址:https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引:https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多,我按照Tauri1的教程来学习&…...