当前位置: 首页 > news >正文

工程化与框架系列(31)--前端依赖管理实践

前端依赖管理实践 📦

引言

前端依赖管理是现代Web开发中的重要环节。本文将深入探讨前端依赖管理的最佳实践,包括包管理工具、版本控制、依赖分析和优化等方面,帮助开发者更好地管理项目依赖。

依赖管理概述

前端依赖管理主要包括以下方面:

  • 包管理工具:npm、yarn、pnpm等
  • 版本控制:语义化版本、锁文件等
  • 依赖分析:依赖树、循环依赖等
  • 依赖优化:体积优化、重复依赖等
  • 安全管理:漏洞检测、更新维护等

依赖管理工具实现

依赖分析器

// 依赖分析器类
class DependencyAnalyzer {private packageJson: PackageJson;private dependencies: Map<string, DependencyInfo>;private devDependencies: Map<string, DependencyInfo>;private nodeModulesPath: string;constructor(projectPath: string) {this.packageJson = this.loadPackageJson(projectPath);this.dependencies = new Map();this.devDependencies = new Map();this.nodeModulesPath = path.join(projectPath, 'node_modules');this.initialize();}// 初始化分析器private initialize(): void {// 分析生产依赖this.analyzeDependencies(this.packageJson.dependencies || {}, false);// 分析开发依赖this.analyzeDependencies(this.packageJson.devDependencies || {}, true);}// 加载package.jsonprivate loadPackageJson(projectPath: string): PackageJson {const packageJsonPath = path.join(projectPath, 'package.json');return require(packageJsonPath);}// 分析依赖private analyzeDependencies(deps: Record<string, string>,isDev: boolean): void {Object.entries(deps).forEach(([name, version]) => {const info = this.analyzeDependency(name, version);if (isDev) {this.devDependencies.set(name, info);} else {this.dependencies.set(name, info);}});}// 分析单个依赖private analyzeDependency(name: string,version: string): DependencyInfo {const packagePath = path.join(this.nodeModulesPath, name);const packageJson = require(path.join(packagePath, 'package.json'));return {name,version: packageJson.version,requiredVersion: version,dependencies: packageJson.dependencies || {},size: this.calculatePackageSize(packagePath),license: packageJson.license,hasTypes: this.hasTypes(name),vulnerabilities: this.checkVulnerabilities(name, packageJson.version)};}// 计算包大小private calculatePackageSize(packagePath: string): number {let size = 0;const files = fs.readdirSync(packagePath);files.forEach(file => {const filePath = path.join(packagePath, file);const stats = fs.statSync(filePath);if (stats.isFile()) {size += stats.size;} else if (stats.isDirectory() && file !== 'node_modules') {size += this.calculatePackageSize(filePath);}});return size;}// 检查是否有类型定义private hasTypes(name: string): boolean {const typesPackage = `@types/${name}`;try {require.resolve(typesPackage);return true;} catch {try {const packageJson = require(path.join(this.nodeModulesPath, name, 'package.json'));return !!packageJson.types || !!packageJson.typings;} catch {return false;}}}// 检查安全漏洞private checkVulnerabilities(name: string,version: string): Vulnerability[] {// 这里应该调用安全数据库API// 示例实现返回模拟数据return [];}// 获取依赖树getDependencyTree(includeDev: boolean = false): DependencyTree {const tree: DependencyTree = {name: this.packageJson.name,version: this.packageJson.version,dependencies: {}};// 添加生产依赖this.dependencies.forEach((info, name) => {tree.dependencies[name] = this.buildDependencySubtree(name);});// 添加开发依赖if (includeDev) {this.devDependencies.forEach((info, name) => {if (!tree.dependencies[name]) {tree.dependencies[name] = this.buildDependencySubtree(name);}});}return tree;}// 构建依赖子树private buildDependencySubtree(name: string,visited: Set<string> = new Set()): DependencyNode {// 检测循环依赖if (visited.has(name)) {return {name,version: 'circular',circular: true,dependencies: {}};}visited.add(name);const info = this.dependencies.get(name) || this.devDependencies.get(name);if (!info) {return {name,version: 'unknown',dependencies: {}};}const node: DependencyNode = {name,version: info.version,dependencies: {}};// 递归构建子依赖Object.entries(info.dependencies).forEach(([depName, depVersion]) => {node.dependencies[depName] = this.buildDependencySubtree(depName,new Set(visited));});return node;}// 查找重复依赖findDuplicateDependencies(): DuplicateDependency[] {const versions: Map<string, Set<string>> = new Map();// 收集所有版本const collectVersions = (tree: DependencyNode,path: string[] = []) => {const key = tree.name;if (!versions.has(key)) {versions.set(key, new Set());}const versionSet = versions.get(key)!;if (tree.version !== 'circular') {versionSet.add(tree.version);}Object.values(tree.dependencies).forEach(dep => {collectVersions(dep, [...path, key]);});};collectVersions(this.getDependencyTree(true));// 查找重复版本const duplicates: DuplicateDependency[] = [];versions.forEach((versionSet, name) => {if (versionSet.size > 1) {duplicates.push({name,versions: Array.from(versionSet)});}});return duplicates;}// 分析依赖大小analyzeDependencySize(): PackageSize[] {const sizes: PackageSize[] = [];// 收集所有包的大小const collectSizes = (tree: DependencyNode,isRoot: boolean = false) => {if (!isRoot) {const info = this.dependencies.get(tree.name) ||this.devDependencies.get(tree.name);if (info) {sizes.push({name: tree.name,version: tree.version,size: info.size});}}Object.values(tree.dependencies).forEach(dep => {collectSizes(dep);});};collectSizes(this.getDependencyTree(true), true);// 按大小排序return sizes.sort((a, b) => b.size - a.size);}// 检查过时依赖async checkOutdatedDependencies(): Promise<OutdatedDependency[]> {const outdated: OutdatedDependency[] = [];// 检查每个依赖的最新版本const checkPackage = async (name: string,currentVersion: string): Promise<void> => {try {const response = await fetch(`https://registry.npmjs.org/${name}`);const data = await response.json();const latestVersion = data['dist-tags'].latest;if (latestVersion !== currentVersion) {outdated.push({name,currentVersion,latestVersion,updateType: this.getUpdateType(currentVersion,latestVersion)});}} catch (error) {console.error(`Failed to check ${name}:`, error);}};// 检查所有依赖const promises = [...this.dependencies.entries()].map(([name, info]) => checkPackage(name, info.version));await Promise.all(promises);return outdated;}// 获取更新类型private getUpdateType(current: string,latest: string): UpdateType {const [currentMajor, currentMinor] = current.split('.').map(Number);const [latestMajor, latestMinor] = latest.split('.').map(Number);if (latestMajor > currentMajor) {return 'major';} else if (latestMinor > currentMinor) {return 'minor';} else {return 'patch';}}
}// 接口定义
interface PackageJson {name: string;version: string;dependencies?: Record<string, string>;devDependencies?: Record<string, string>;
}interface DependencyInfo {name: string;version: string;requiredVersion: string;dependencies: Record<string, string>;size: number;license: string;hasTypes: boolean;vulnerabilities: Vulnerability[];
}interface DependencyTree {name: string;version: string;dependencies: Record<string, DependencyNode>;
}interface DependencyNode {name: string;version: string;circular?: boolean;dependencies: Record<string, DependencyNode>;
}interface Vulnerability {id: string;severity: 'low' | 'medium' | 'high' | 'critical';description: string;fixedIn?: string;
}interface DuplicateDependency {name: string;versions: string[];
}interface PackageSize {name: string;version: string;size: number;
}interface OutdatedDependency {name: string;currentVersion: string;latestVersion: string;updateType: UpdateType;
}type UpdateType = 'major' | 'minor' | 'patch';// 使用示例
const analyzer = new DependencyAnalyzer(process.cwd());// 获取依赖树
const tree = analyzer.getDependencyTree(true);
console.log('Dependency Tree:', JSON.stringify(tree, null, 2));// 查找重复依赖
const duplicates = analyzer.findDuplicateDependencies();
console.log('Duplicate Dependencies:', duplicates);// 分析依赖大小
const sizes = analyzer.analyzeDependencySize();
console.log('Package Sizes:', sizes);// 检查过时依赖
analyzer.checkOutdatedDependencies().then(outdated => {console.log('Outdated Dependencies:', outdated);
});

依赖更新器

// 依赖更新器类
class DependencyUpdater {private packageJson: PackageJson;private packageJsonPath: string;private lockFilePath: string;constructor(projectPath: string) {this.packageJsonPath = path.join(projectPath, 'package.json');this.lockFilePath = path.join(projectPath, 'package-lock.json');this.packageJson = require(this.packageJsonPath);}// 更新单个依赖async updateDependency(name: string,version: string,isDev: boolean = false): Promise<void> {// 更新package.jsonconst dependencies = isDev? this.packageJson.devDependencies: this.packageJson.dependencies;if (!dependencies) {throw new Error(`No ${isDev ? 'dev ' : ''}dependencies found`);}dependencies[name] = version;// 写入package.jsonawait this.writePackageJson();// 运行npm installawait this.runNpmInstall();}// 批量更新依赖async updateDependencies(updates: DependencyUpdate[]): Promise<void> {// 更新package.jsonupdates.forEach(update => {const dependencies = update.isDev? this.packageJson.devDependencies: this.packageJson.dependencies;if (dependencies) {dependencies[update.name] = update.version;}});// 写入package.jsonawait this.writePackageJson();// 运行npm installawait this.runNpmInstall();}// 更新所有依赖到最新版本async updateAllToLatest(includeDev: boolean = false): Promise<void> {const updates: DependencyUpdate[] = [];// 收集生产依赖更新if (this.packageJson.dependencies) {const prodUpdates = await this.collectLatestVersions(this.packageJson.dependencies,false);updates.push(...prodUpdates);}// 收集开发依赖更新if (includeDev && this.packageJson.devDependencies) {const devUpdates = await this.collectLatestVersions(this.packageJson.devDependencies,true);updates.push(...devUpdates);}// 批量更新await this.updateDependencies(updates);}// 收集最新版本信息private async collectLatestVersions(dependencies: Record<string, string>,isDev: boolean): Promise<DependencyUpdate[]> {const updates: DependencyUpdate[] = [];for (const [name, currentVersion] of Object.entries(dependencies)) {try {const response = await fetch(`https://registry.npmjs.org/${name}`);const data = await response.json();const latestVersion = data['dist-tags'].latest;if (latestVersion !== currentVersion) {updates.push({name,version: latestVersion,isDev});}} catch (error) {console.error(`Failed to check ${name}:`, error);}}return updates;}// 写入package.jsonprivate async writePackageJson(): Promise<void> {await fs.promises.writeFile(this.packageJsonPath,JSON.stringify(this.packageJson, null, 2));}// 运行npm installprivate async runNpmInstall(): Promise<void> {return new Promise((resolve, reject) => {const npm = spawn('npm', ['install'], {stdio: 'inherit'});npm.on('close', code => {if (code === 0) {resolve();} else {reject(new Error(`npm install failed with code ${code}`));}});});}// 清理未使用的依赖async cleanUnusedDependencies(): Promise<string[]> {const removed: string[] = [];// 获取已安装的依赖const nodeModules = await fs.promises.readdir(path.join(process.cwd(), 'node_modules'));// 获取package.json中声明的依赖const declaredDeps = new Set([...Object.keys(this.packageJson.dependencies || {}),...Object.keys(this.packageJson.devDependencies || {})]);// 查找未使用的依赖for (const module of nodeModules) {if (module.startsWith('@')) {// 处理作用域包const scopedModules = await fs.promises.readdir(path.join(process.cwd(), 'node_modules', module));for (const scopedModule of scopedModules) {const fullName = `${module}/${scopedModule}`;if (!declaredDeps.has(fullName)) {removed.push(fullName);}}} else if (!declaredDeps.has(module)) {removed.push(module);}}// 删除未使用的依赖for (const module of removed) {await fs.promises.rm(path.join(process.cwd(), 'node_modules', module),{ recursive: true });}return removed;}// 生成依赖报告async generateDependencyReport(): Promise<DependencyReport> {const analyzer = new DependencyAnalyzer(process.cwd());return {tree: analyzer.getDependencyTree(true),duplicates: analyzer.findDuplicateDependencies(),sizes: analyzer.analyzeDependencySize(),outdated: await analyzer.checkOutdatedDependencies()};}
}// 接口定义
interface DependencyUpdate {name: string;version: string;isDev: boolean;
}interface DependencyReport {tree: DependencyTree;duplicates: DuplicateDependency[];sizes: PackageSize[];outdated: OutdatedDependency[];
}// 使用示例
const updater = new DependencyUpdater(process.cwd());// 更新单个依赖
updater.updateDependency('lodash', '^4.17.21');// 更新多个依赖
updater.updateDependencies([{ name: 'react', version: '^18.0.0', isDev: false },{ name: 'typescript', version: '^5.0.0', isDev: true }
]);// 更新所有依赖到最新版本
updater.updateAllToLatest(true);// 清理未使用的依赖
updater.cleanUnusedDependencies().then(removed => {console.log('Removed unused dependencies:', removed);
});// 生成依赖报告
updater.generateDependencyReport().then(report => {console.log('Dependency Report:', report);
});

最佳实践与建议

  1. 版本管理

    • 使用语义化版本
    • 锁定依赖版本
    • 定期更新依赖
    • 版本兼容性测试
  2. 依赖优化

    • 删除未使用依赖
    • 合并重复依赖
    • 拆分开发依赖
    • 优化包体积
  3. 安全管理

    • 定期安全检查
    • 及时修复漏洞
    • 审核新依赖
    • 维护依赖白名单
  4. 工程实践

    • 使用monorepo
    • 依赖共享策略
    • 构建优化
    • CI/CD集成

总结

前端依赖管理需要考虑以下方面:

  1. 依赖版本管理
  2. 依赖分析与优化
  3. 安全漏洞防护
  4. 构建性能优化
  5. 工程化实践

通过合理的依赖管理策略,可以提高项目的可维护性和安全性。

学习资源

  1. npm官方文档
  2. 语义化版本规范
  3. 依赖管理最佳实践
  4. 安全漏洞数据库
  5. 构建优化指南

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

相关文章:

工程化与框架系列(31)--前端依赖管理实践

前端依赖管理实践 &#x1f4e6; 引言 前端依赖管理是现代Web开发中的重要环节。本文将深入探讨前端依赖管理的最佳实践&#xff0c;包括包管理工具、版本控制、依赖分析和优化等方面&#xff0c;帮助开发者更好地管理项目依赖。 依赖管理概述 前端依赖管理主要包括以下方面…...

【vscode-01】vscode不同项目不同语言扩展插件隔离方案

vscode不同项目不同语言扩展插件隔离方案 1. 背景2. vscode 扩展插件隔离方案2.1 code-profile 配置文件2.2 配合extensions.json 1. 背景 最近打开vscode 发现越来越卡&#xff0c;这是一个轻量级代码编辑器&#xff0c;怎么会如此占用内存呢&#xff1f; 我使用了‘code --l…...

17 | 实现简洁架构的 Biz 层

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b;欢迎加入 云原生 AI 实战 星球&#xff0c;12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力&#xff08;聚焦于 Go、云原生、AI Infra&#xff09;&#xff1b;本节课最终…...

DNS解析错误要怎么处理

在互联网时代&#xff0c;网络已经成为人们生活和工作中不可或缺的一部分。然而&#xff0c;当遇到DNS 解析错误时&#xff0c;原本畅通无阻的网络访问会突然陷入困境&#xff0c;让人感到十分困扰。DNS&#xff0c;即域名系统&#xff0c;它如同互联网的电话簿&#xff0c;将人…...

【Rust基础】Rust后端开发常用库

使用Rust有一段时间了&#xff0c;期间尝试过使用Rust做后端开发、命令行工具开发&#xff0c;以及做端侧模型部署&#xff0c;也尝试过交叉编译、FFI调用等&#xff0c;也算是基本入门了。在用Rust做后端接口开发时&#xff0c;常常会找不到一些合适库&#xff0c;而这些库在J…...

【附JS、Python、C++题解】Leetcode面试150题(9)——三数之和

一、题目​​​​​ 15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足&#xff1a; i!j、i!k 且 j! k &#xff0c;同时还满足&#xff1a;nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意…...

脑电波控制设备:基于典型相关分析(CCA)的脑机接口频率精准解码方法

文章目录 前言一、CCA的用途二、频率求解思路三、输入数据结构四、判断方法五、matlab实践1.数据集获取及处理2.matlab代码3.运行及结果 六、参考文献 前言 在脑机接口(BCI)领域&#xff0c;有SSVEP方向&#xff0c;中文叫做稳态视觉诱发电位&#xff0c;当人观看闪烁的视觉刺激…...

Golang学习笔记_44——命令模式

Golang学习笔记_41——观察者模式 Golang学习笔记_42——迭代器模式 Golang学习笔记_43——责任链模式 文章目录 一、核心概念1. 定义2. 解决的问题3. 核心角色4. 类图 二、特点分析三、适用场景1. 事务管理系统2. 多媒体遥控器3. 操作审计系统 四、Go语言实现示例五、高级应用…...

vue项目如何实现条件查询?

目录 1.前端 2.后端 3.mybatis的sql语句 结语 1.前端 说白了就是&#xff0c;无论该参数是否是空字符串&#xff0c;都会传递到后端。&#xff08;反正不是null就行&#xff09;。 2.后端 在controller层中&#xff0c;使用RequestParam注解接收名为registerName的参数&…...

windows平台的ffmpeg编译使用

windows平台的ffmpeg编译使用 一、现状 本人使用libgdx开发galGame,发现扩展包gdx-video不支持mp4,不能忍,正好看到官网有支持自定义编译的文档,所以操作一下,自定义编译。本文重点在于操作windows平台,linux平台太简单了。 整个过程包括如下几个步骤。 二、代码下载…...

Android 14 昼夜色切换多屏时候非主屏的Activity无法收到onConfigurationChanged

记录一下遇见的这个问题和查看源码的过程 首先先说遇见的问题 Android 14 昼夜色切换多屏时候 非主屏的Activity 会经常收不到 onConfigurationChanged的回调 分析原因源码中ActivityThread::performActivityConfigurationChanged 里面 private Configuration performActivi…...

NLP常见任务专题介绍(4)-ConditionalGeneration和CasualLM区别

在 transformers 库中,ConditionalGeneration 和 CausalLM 是两种不同类型的语言模型,各自适用于不同的任务: 类别Conditional Generation (条件生成)CausalLM (因果语言模型)核心区别依赖输入 条件 生成文本只能 自回归 生成文本训练方式Encoder-Decoder(编码-解码) 结构…...

【vue+excel】导出excel(目前是可以导出两个sheet)

项目里经常用到的导出ecxel功能是默认导出一个sheet页 现在需要导出两个sheet&#xff0c;一个是总计&#xff0c;另一个是明细 效果如下&#xff1a; 我就在现有的单个导出的功能上改造了一下&#xff0c;只支持导出两个&#xff08;代码不够灵活&#xff0c;如果需要多个&…...

【数据结构】6栈

0 章节 3&#xff0e;1到3&#xff0e;3小节。 认知与理解栈结构&#xff1b; 列举栈的操作特点。 理解并列举栈的应用案例。 重点 栈的特点与实现&#xff1b; 难点 栈的灵活实现与应用 作业或思考题 完成学习测试&#xff12;&#xff0c;&#xff1f; 内容达成以下标准(考核…...

【C++】每日一练(有效的括号)

本篇博客给大家带来的是用C语言来解答有效的括号&#xff01; &#x1f41f;&#x1f41f;文章专栏&#xff1a;每日一练 &#x1f680;&#x1f680;若有问题评论区下讨论&#xff0c;我会及时回答 ❤❤欢迎大家点赞、收藏、分享&#xff01; 今日思想&#xff1a;不服输的少年…...

数字化新零售与 AI 大模型,如何重塑大健康赛道?​

在数字化浪潮中&#xff0c;大健康赛道正经历深刻变革。数字化新零售营销模式的兴起&#xff0c;与 AI 大模型的强大能力相结合&#xff0c;为大健康领域带来了全新的发展机遇。 数字化新零售营销模式融合线上线下&#xff0c;运用大数据、云计算分析消费者行为&#xff0c;实…...

Android实现Socket通信

问题&#xff1a; 我在Android端对接后端Socket服务实现消息模块的时候&#xff0c;使用WebSocketClient 库&#xff0c;手动构造了订阅和发送消息的 STOMP 帧&#xff0c;&#xff0c;Socket连接成功建立&#xff0c;但是当用户发送消息的时候&#xff0c;对方无法接受到。 …...

✅ Vue 3 响应式写法小抄表(Composition API 实战模板)

&#x1f4e6; 引入核心响应式工具 import { ref, reactive, computed, watch, toRefs } from vue1️⃣ 基本类型&#xff08;string / number / boolean&#xff09; → 推荐使用 ref() const username ref() const count ref(0) const isLoading ref(false)2️⃣ 对象/表…...

Python数据分析之数据可视化

Python 数据分析重点知识点 本系列不同其他的知识点讲解&#xff0c;力求通过例子让新同学学习用法&#xff0c;帮助老同学快速回忆知识点 可视化系列&#xff1a; Python基础数据分析工具数据处理与分析数据可视化机器学习基础 四、数据可视化 图表类型与选择 根据数据特…...

TCP协议支持全双工原因TCP发送接收数据是生产者消费者模型

一、TCP支持全双工的原因 TCP协议支持全双工&#xff0c;即使用TCP协议进行通信时&#xff0c;服务端和客户端可以同时进行数据的发送和接收&#xff0c;互不干扰&#xff0c;实现同时双向传输数据。 这是因为使用TCP协议通信时&#xff0c;读写套接字的文件描述符既用来发送…...

【ODHead】BEVDet的 CenterHead的推理和拓展到蒸馏损失的算法细节

文章目录 背景常识1、BEVDet的CenterHead整体方案2、蒸馏部分3、输出 preds_dicts 部分3.1、headmap3.2、bbox3.3、Mask掩膜3.4、损失 背景常识 在BEVDet和BEVFormer里&#xff0c;使用了不同的3D detection head&#xff08;BEVDet用了centerhead&#xff0c;BEVFormer用了de…...

在 CentOS 7 上安装 PHP 7.3

在 CentOS 7 上安装 PHP 7.3 可以按照以下步骤进行操作&#xff1a; 1. 安装必要的依赖和 EPEL 仓库 EPEL&#xff08;Extra Packages for Enterprise Linux&#xff09;是为企业级 Linux 提供额外软件包的仓库&#xff0c;yum-utils 用于管理 yum 仓库。 sudo yum install -…...

vue+dhtmlx-gantt 实现甘特图-快速入门【甘特图】

文章目录 一、前言二、使用说明2.1 引入依赖2.2 引入组件2.3 引入dhtmlx-gantt2.4 甘特图数据配置2.5 初始化配置 三、代码示例3.1 Vue2完整示例3.2 Vue3 完整示例 四、效果图 一、前言 dhtmlxGantt 是一款功能强大的甘特图组件&#xff0c;支持 Vue 3 集成。它提供了丰富的功…...

关于ModbusTCP/RTU协议对接Ethernet/IP(CIP)协议的方案

IGT-DSER智能网关模块支持西门子、倍福(BECKHOFF)、罗克韦尔AB&#xff0c;以及三菱、欧姆龙等各种品牌的PLC之间通讯&#xff0c;支持Ethernet/IP(CIP)、Profinet(S7)&#xff0c;以及FINS、MC等工业自动化常用协议&#xff0c;同时也支持PLC与Modbus协议的工业机器人、智能仪…...

python-leetcode 49.二叉树中的最大路径和

题目&#xff1a; 二叉树中的路径被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边&#xff0c;同一个节点在一条路径序列中至多出现一次&#xff0c;该路径至少包含一个节点&#xff0c;且不一定经过根节点。 路径和是路径中各节点值得总和&#xff0c;…...

C语言基础知识04

指针 指针概念 指针保存地址&#xff0c;地址是字节的编号 指针类型和保存的地址类型要一直 使用时注意&#xff0c;把地址转换为&变量的格式来看 int a[3]; a转为&a[0] 指针的大小 64bit 固定8字节&#xff0c; 32bit 固定4字节 指针…...

使用 Golang 操作 MySQL

在Go语言中&#xff0c;操作SQL数据库&#xff0c;通常会用到一些第三方库来简化数据库的连接、查询和操作过程。其中原生的 database/sql go-sql-driver/mysql 库更符合sql语句使用习惯。‌ 安装 go get github.com/go-sql-driver/mysql 直接上代码来演示基本的创建&#xff…...

前端面试:cookie 可以实现不同域共享吗?

在前端开发中&#xff0c;Cookie 不能直接实现不同域之间的共享。Cookie 的作用域受到域的限制&#xff0c;浏览器不会允许一个域下的 Cookie 被另一个域访问。这是为了保护用户隐私及安全&#xff0c;防止跨站请求伪造&#xff08;CSRF&#xff09;等安全问题。 Cookie 的基本…...

MyBatis-Plus接入和简单使用

如何接入 https://baomidou.com/getting-started/ 简单使用方法 使用 MyBatis-Plus 时&#xff0c;大多数场景下不需要编写 XML 和 SQL&#xff0c;因为它提供了强大的通用 CRUD 操作和条件构造器。但以下情况可能需要手动编写 SQL&#xff1a; 1. 不需要写 XML/SQL 的场景 …...

【Go万字洗髓经】Golang内存模型与内存分配管理

本文目录 1. 操作系统中的虚拟内存分页与进程管理虚拟内存与内存隔离 2. Golang中的内存模型内存分配流程内存单元mspan线程缓存mcache中心缓存mcentral全局堆缓存mheapheapArena空闲页索引pageAlloc 3. Go对象分配mallocgc函数tiny对象分配内存 4.结合GMP模型来看内存模型tiny…...

mov格式视频如何转换mp4?

mov格式视频如何转换mp4&#xff1f;在日常的视频处理中&#xff0c;经常需要将MOV格式的视频转换为MP4格式&#xff0c;以兼容更多的播放设备和平台。下面给大家分享如何将MOV视频转换为MP4&#xff0c;4款视频格式转换工具分享。 一、牛学长转码大师 牛学长转码大师是一款功…...

鸿蒙OS开发ForEach循环渲染

摘要 在ForEach循环渲染过程中&#xff0c;如果修改列表项中的数据&#xff0c;但是UI页面不会刷新。在最近开发公司app时遇到了这个问题&#xff0c;经过查看官方文档找到了解决方式 官方地址&#xff1a;数据变化不刷新 一、具体解决方案 思路&#xff1a;通过父子组件传…...

【算法】DFS、BFS、拓扑排序

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;算法 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 持续更新中...1、DFS2、BFSN 叉树的层序遍历二叉树的锯齿形层序遍历二叉树最大宽度 3、多源BFS腐烂的苹果 4、拓扑排序 持续更新中…...

【Godot4.0】贝塞尔曲线在游戏中的实际应用

概述 之前研究贝塞尔曲线绘制&#xff0c;完全是以绘图函数&#xff0c;以及实现节点连接为思考。并没有实际考虑贝塞尔曲线在游戏中的应用。今日偶然看到悦千简一年多前发的一个用贝塞尔曲线实现追踪弹或箭矢效果&#xff0c;还有玩物不丧志的老李杀戮尖塔系列中的卡牌动态箭…...

MongoDB 数据导出与导入实战指南(附完整命令)

1. 场景说明 在 MongoDB 运维中&#xff0c;数据备份与恢复是核心操作。本文使用 mongodump 和 mongorestore 工具&#xff0c;演示如何通过命令行导出和导入数据&#xff0c;解决副本集连接、路径指定等关键问题。 2. 数据导出&#xff08;mongodump&#xff09; 2.1 导出命…...

『Rust』Rust运行环境搭建

文章目录 rust编译工具rustupVisual Studio VS Code测试编译手动编译VSCode编译配置 参考完 rust编译工具rustup https://www.rust-lang.org/zh-CN/tools/install 换源 RUSTUP_DIST_SERVER https://rsproxy.cn RUSTUP_UPDATE_ROOT https://rsproxy.cn修改rustup和cargo的安…...

CPU+GPU结合的主板设计思路与应用探讨

在高性能计算和图形处理需求不断增长的背景下&#xff0c;CPUGPU结合的主板设计逐渐成为硬件架构的重要趋势。本文将探讨基于CPUGPU架构的主板设计思路、关键技术考量以及应用前景。 1. 设计思路概述 CPU&#xff08;中央处理器&#xff09;擅长处理复杂的逻辑运算和多任务控制…...

latex问题汇总

latex问题汇总 环境问题1 环境 texlive2024 TeXstudio 4.8.6 (git 4.8.6) 问题1 编译过程有如下错 ! Misplaced alignment tab character &. l.173 International Conference on Infrared &Millimeter Waves, 2004: 667--... I cant figure out why you would wa…...

学习springboot-Bean管理(Bean 注册,Bean 扫描)

Bean 扫描 可以浏览下面的博客链接 &#xff1a;spring 学习 &#xff08;注解&#xff09;-CSDN博客 在学习spring 注解时&#xff0c;我们使用 Component &#xff0c;Service,Controller等 这样的注解&#xff0c;将目标类信息&#xff0c;传递给IOC容器&#xff0c;为其创…...

iOS开发,SQLite.swift, Missing argument label ‘value:‘ in call问题

Xcode16中&#xff0c;集成使用SQLite.swift&#xff0c;创建表的时候&#xff1a; let id Expression<Int64>("id")&#xff0c;报错Missing argument label value: in call 直接使用SQLite.Expression<Int64>("id") 或者定义一个全局typ…...

【GIT】重新初始化远程仓库

有的时候我们克隆远端仓库会出错&#xff1a; git clone --depth 1 git116.*.*.*:/srv/customs.git D:\dev\projects\kdy\customs11\customs Cloning into D:\dev\projects\kdy\customs11\customs... remote: Enumerating objects: 1494, done. remote: Counting objects: 100…...

Vue3中 ref 与 reactive区别

ref 用途: ref 通常用于创建一个响应式的基本类型数据&#xff08;如 string、number、boolean 等&#xff09;&#xff0c;但它也可以用于对象或数组 返回值: ref 返回一个带有 .value 属性的对象&#xff0c;访问或修改数据需要通过 .value 进行 使用场景: …...

apollo3录音到wav播放解决方法

SDK DEMO项目:ap3bp_evb_vos_pcm_recorder_20210901 pcm_recorder.c //***************************************************************************** // // Options // //***************************************************************************** #define PRINT…...

信号处理抽取多项滤波的数学推导与仿真

昨天的《信号处理之插值、抽取与多项滤波》&#xff0c;已经介绍了插值抽取的多项滤率&#xff0c;今天详细介绍多项滤波的数学推导&#xff0c;并附上实战仿真代码。 一、数学变换推导 1. 多相分解的核心思想 将FIR滤波器的系数 h ( n ) h(n) h(n)按相位分组&#xff0c;每…...

Java网络多线程

网络相关概念: 关于访问: IP端口 因为一个主机上可能有多个服务, 一个服务监听一个端口,当你访问的时候主机通过端口号就能知道要和哪个端口发生通讯.因此一个主机上不能有两个及以上的服务监听同一个端口. 协议简单来说就是数据的组织形式 好像是两个人交流一样,要保证自己说…...

linux centos 忘记root密码拯救

在CentOS 7中&#xff0c;如果忘记root密码&#xff0c;可以通过修改系统启动参数进入单用户模式或紧急模式进行重置。以下是两种常用方法&#xff0c;适用于物理机或虚拟机环境&#xff1a; 方法一&#xff1a;通过rd.break参数重置密码 步骤&#xff1a; 重启系统并进入GRU…...

C# 事件使用详解

总目录 前言 在C#中&#xff0c;事件&#xff08;Events&#xff09;是一种基于委托的重要机制&#xff0c;用于实现对象之间的松耦合通信。它通过发布-订阅模式&#xff08;Publisher-Subscriber Pattern&#xff09;&#xff0c;允许一个对象&#xff08;发布者&#xff09;…...

flink cdc同步mysql数据

一、api 添加依赖 <dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-mysql-cdc</artifactId><!-- 请使用已发布的版本依赖&#xff0c;snapshot 版本的依赖需要本地自行编译。 --><version>3.3-SNAP…...

tomcat负载均衡配置

这里拿Nginx和之前做的Tomcat 多实例来实现tomcat负载均衡 1.准备多实例与nginx tomcat单机多实例部署-CSDN博客 2.配置nginx做负载均衡 upstream tomcat{ server 192.168.60.11:8081; server 192.168.60.11:8082; server 192.168.60.11:8083; } ser…...

Ceph(1):分布式存储技术简介

1 分布式存储技术简介 1.1 分布式存储系统的特性 &#xff08;1&#xff09;可扩展 分布式存储系统可以扩展到几百台甚至几千台的集群规模&#xff0c;而且随着集群规模的增长&#xff0c;系统整体性能表现为线性增长。分布式存储的水平扩展有以下几个特性&#xff1a; 节点…...