Monorepo架构: 项目管理工具介绍、需求分析与技术选型

微前端 前置知识2--- monorepo架构 我们采用的是微前端一个主应用,和多个子应用,我们肯定不会一个一个去install安装依赖,太傻了,我们采用monorepo 架构 一次install 即可安装完成。第一步需要安装pnpmpnpm内置了对单个代码仓库包含多个软件包的支持,是monorepo架构模式的不二速选。 阅读详情

概述

  • 如何实现 monorepo,以及在项目中如何管理多个包,在进行具体项目开发前,有必要强调一个重要思维 — 全局观

  • 即看待技术方案时,要从需求角度出发,综合考量该方案能否长远满足项目或团队需求

  • 为什么要有全局观呢?如果直接拿一个项目,用特定工具创建工作区间并将其作为 monorepo 项目使用,虽直观易感受,但当技术更新时,这种思维方式就会落后

  • 若站在更高视角了解新技术、新方向,先梳理相关工具,明确哪些工具可满足需求,虽前期会花费一些时间,但后续不论遇到何种工具,都能清楚其用途

  • 这种方法可称作比较学习法,能举一反三、触类旁通,学会多种技术,横向比较了三类与 monorepo 相关的应用场景工具

  • 建立全局观后,后续在进行包管理和构建相关的技术选型时,就能更有针对性

  • 目前与 monorepo 相关的工具可分为三类,前两类尤为重要,需带着问题研究

    • 包管理与版本控制:例如 NPM、Lerna 等工具
    • 构建和测试优化:需要带着疑问去探究其含义
    • 组件化流程化开发:这是前端常涉及的内容
  • 解决包管理问题后,更重要的是形成自动化流水化,并提高其效率

  • 构建和测试优化环节便是在包管理基础上加入缓存、服务端优化等,以提升自动化流水线和整体开发效率

包管理与版本控制

  • 下面先从包管理和版本控制部分开始,重点介绍三个方案:
    • Learner:用于管理多个应用源代码的工具,很多项目曾使用该工具,但官方已切换至 pnpm
    • pnpm 和 Yarn Workspaces:二者类似,都可在同一工作区间管理多个 package 的依赖项。Pnpm Space 和 Yarn Workspaces 能在每个项目中独立使用 package.json 管理对应依赖

构建和测试优化相关的工具

  • NX:功能全面,具有缓存增量、并行构建、分布式构建等特点,还包含云平台相关功能,涉及构建、发布及云平台工具功能。其维护团队与 Leana 团队有一定关联,可与 Leana 5.1 以上版本集成,二者是互补关系

  • Turborepo:近年来流行的工具,底层用 Rush 编写。具有性能优化(采用高效缓存和任务调度策略)、依赖管理(智能处理依赖关系)、可扩展性(能处理不同规模项目的构建测试)、集成支持(与现有工具框架无缝集成)、远程缓存(提供服务端远程缓存加速构建)等特点,可视为 NX 的子集

  • Rush:微软出品,专为 monorepo 项目打造,主要解决两个问题:

    • 幽灵依赖:指在 package.json 文件中未明确列出,但安装时必须安装的包,可能导致项目在不同环境运行结果不同
    • 依赖包多副本问题:即同一个依赖包的多个版本同时存在于项目中,使依赖关系复杂,易引发引用混乱。Rush 还支持并行构建、插件系统和项目发布

组件化和模块化开发相关工具

  • Bit:使用 PNPM 管理项目依赖,是商业化工具。其颗粒度小到组件级别,可将 React 等框架中的组件或函数单独封装发布,具有灵活、便捷、可插拔、无需过多维护等优点,适用于多种场景,支持多种项目类型。

  • Layer- pack:是Webpack Plugin, 主要管理导入的 Glow 选项,聚焦于 Webpack 生态,可继承 Webpack 相关配置,适用于已有 Webpack 项目且想采用特定架构的情况

基于 Yarn Workspace 的 Monorepo 项目实践指南

1 ) 环境准备

  • 先从包管理相关工具开始, 首先,查看本地环境,我使用的是 Node 的 LTS 版本,然后全局安装 yarn
  • 推荐安装 nrm 并使用它切换到淘宝源。我已经切换成功,可以通过 npm config get registry 查看,现在已经切换到淘宝源了。将淘宝源复制,然后使用 yarn config set registry 设置为淘宝源,这样使用 yarn 工具安装依赖项时就会使用淘宝源,加速安装过程,npm 则不用管

2 ) 创建项目目录与初始化

  • 创建一个空目录,使用 mkdir yarnworkspacedemo 命令,也可以右键创建
  • 我直接使用命令行创建,接下来使用 yarn init -y 初始化项目
  • 初始化完成后,用 VSCode 打开 package.json 文件

3 ) 设置 yarn workspace 项目

  • 要设置一个 yarn workspace 的项目(即命名空间项目)来管理模块,需要修改 package.json 文件,在其中设置 workspaces 属性,并指定目录。
  • 接着创建一个 packages 目录,在其下面创建对应的模块,例如 moduleA 和 moduleB,这两个模块实际上就是两个 npm 包。
  • 在 packages/moduleA 和 packages/moduleB 目录下,分别使用 yarn init -y 初始化 package.json 文件,这样每个模块就有独立的文件来记录其相关依赖。

4 ) 添加依赖项

  • 在子模块中添加依赖:可以 cd 到子模块目录下,使用 yarn add 命令添加对应的依赖
  • 在根目录为所有模块添加依赖:直接在根目录使用 yarn add lodash -w 命令,这里的 -w 表示为所有工作区添加依赖。但要注意,根目录的 package.json 中需要设置 private: true 和 workspaces 属性项。执行该命令后,会更新根目录的 package.json 文件,但子目录中不会显示依赖,但在子模块中调用依赖的方法时可以正常使用,这得益于 Node 的包管理机制,它会向上查找父级目录中的依赖
  • 在特定子模块中添加依赖:使用 yarn workspace moduleA add <dependency> 命令,可以限定在某个模块中添加依赖项,此时只会更新该子模块的 package.json 文件

6 ) 处理依赖版本冲突

  • 如果在子目录中指定了某个依赖的版本,而根目录中又指定了不同的版本,yarn 会在子目录中单独安装一份指定版本的依赖。
  • 例如,在子目录中添加 lodash 版本为 3,在根目录中添加 lodash 版本为 4,子目录中会单独创建一个 node_modules 目录来存放版本为 3 的 lodash,而根目录的 node_modules 中存放版本为 4 的 lodash。

7 ) 跨模块使用

  • 若要在 moduleB 中使用 moduleA 导出的方法,先在 moduleA 中导出方法,如使用 CommonJS 规范:

    const range = (x, y) => { 
      // 方法实现 
      return [x, y]; 
    }; 
    module.exports = range; 
    
  • 然后在 moduleB 中使用 yarn workspace moduleB add moduleA 添加依赖, 但可能会遇到版本号问题,这是因为 npm 上可能有同名的包。解决方法有两种:

    • 修改包名:给包名添加命名空间,如 @yournamespace/moduleA,确保名称独一无二。
    • 使用文件引用:在 package.json 中使用文件路径引用,如 "./packages/moduleA"

8 ) 创建新模块及处理未发布模块引用

  • 创建一个新模块 moduleC,在 packages/moduleC 目录下使用 yarn init -y 初始化,并设置包名时使用 @命名空间/包名 的格式,包名建议使用小写英文加中短横线,且不以点号或下横线开头。

  • 若要在 moduleB 中安装还未发布的 moduleC,不能直接使用 yarn workspace moduleB add moduleC,会报错。正确做法是先 cd 到根目录,使用 yarn install 命令在 node_modules 下创建软链接。执行后若没有成功链接,可以清除缓存,删除 node_modules 目录,再次执行 yarn install。此时在 moduleB 中可以使用 require('moduleC') 引用 moduleC,但 moduleB 的 package.json 中不会更新 moduleC 的依赖信息。若要更新,需要手动在 moduleB 的 package.json 的 dependencies 部分添加 moduleC 的具体版本。

9 ) 注意事项

  • 文件协议引用的问题:如果使用文件协议引用模块(如 file:./packages/moduleA),模块会被视为外部依赖,而不是工作区的一部分。每次更新模块代码后,需要清除 node_modules 缓存,重新执行 yarn install,比较麻烦。
  • 使用 yarn workspace 的要点总结:
    • 在项目根目录的 package.json 中配置 workspaces 属性,添加多个文件目录交给 yarn 管理。
    • 管理模块可以使用 yarn workspace <模块名> <命令> 的方式,也可以直接 cd 到该目录使用常用命令,yarn 会自动管理多个不同包下同名依赖的不同版本号。若与根目录中的依赖冲突,会在该包下创建 node_modules 目录并下载一份新的依赖。
    • 模块未发布时使用 yarn 关联本地依赖,可能会下载到别人创建的同名包,解决方法是命名一个独特的名称。跨模块使用时,可以使用 module:* 方式配合 yarn install 让包在整个工作区中关联,但还需执行 yarn install 在工作区目录的 node_modules 中创建对应的软链接。
    • 包名最好使用 @命名空间/包名 的结构,采用小写英文加中短横线的方式命名,避免以点号或下横线开头

PMPM Workspace使用教程、依赖包管理操作

1 ) 创建PNPM Workspace

  • 创建空目录:首先创建一个空的目录,我在这里创建了一个名为“PNPMworkspacedemo”的目录。
  • 打开workspace:使用workspace将其打开。
  • 初始化package.json文件:在终端工具中,使用pnpm init -y初始化一个package.json文件。
  • 创建pnpm-workspace.yaml文件:在该目录中创建一个名为pnpm-workspace.yaml的文件,在文件里添加一个字段packages,换行后接上文件的目录。例如,packages/ 表示只要是packages目录下面的包,相当于moderator项目,就是受PNPM workspace管理的模块。你也可以添加其他目录,比如folder1、folder2等(若根目录中没有这些目录,可以将其注释掉)。这样,PNPM的workspace就创建好了。

2 ) 创建模块并初始化

  • 创建module-a和module-b两个模块,和之前一样,在这两个目录中初始化package.json文件。打开终端工具,执行以下命令:
  • cd packages/module-a 然后 pnpm init -y
  • cd packages/module-b 然后 pnpm init -y

3 ) 安装依赖包

  • 在根目录安装依赖:在根目录执行pnpm install lodash命令,会提示需要有pnpm-workspace.yaml文件。若文件名字写错,修改后再次安装,需要加上-w参数,这样依赖项会安装在根目录,module-a和module-b可以引用根目录中的模块,但这些模块不会打包到module-a或module-b中。
  • 在指定模块安装特定版本依赖:若要在module-a中安装特定版本的lodash,可以使用--filter参数,例如pnpm install lodash@3 --filter=module-a ,执行后在module-a的package.json里会多出一个lodash的依赖项。也可以使用pnpm install lodash@2 --filter module-a 这种格式。
  • 模块间依赖安装:在module-b中引用module-a,可以使用pnpm add module-a命令。安装后,node_modules下面的依赖包会有一个小箭头,表示这些文件是在全局引用的,存放在PNPM的缓存目录中,这样可以节省磁盘空间。

4 ) 查看和设置PNPM缓存目录

  • 查看缓存目录:使用pnpm store path命令可以查看本地的PNPM store位置,使用文件管理工具打开该目录,里面存放着很多下载的包和文件。
  • 设置缓存路径:使用pnpm config set store-dir ~/.pnpm-store命令可以设置缓存路径,设置成功后,后续安装依赖包时,若提示需要重新rebuild store ,按照提示操作即可。也可以使用pnpm config delete store-dir命令将缓存路径恢复到默认情况。

5 ) 模块代码编写与测试

  • 在module-a和module-b中编写代码进行测试。例如,在module-a中引入lodash:
    const _ = require('lodash'); 
    const range = _.range; 
    module.exports = range; 
    
  • 在module-b中引用module-a:
    const range = require('module-a'); 
    console.log(range(1, 10)); 
    
  • 保存代码后,若要执行代码,可以使用不同的命令:
    • 执行所有模块的脚本:PNPM提供了-r命令,例如pnpm -r exec node index.js ,可以循环执行各个模块中的index.js文件。在多个模块需要运行测试脚本的场景中,就可以使用pnpm -r exec 加上测试脚本的执行命令,让PNPM循环执行每个包中的测试脚本。
    • 执行特定模块的脚本:若要执行module-a中的start脚本,可以使用pnpm --filter=module-a run start (建议写filter时带上引号,避免出现问题)。

6 ) 简化命令设置
对于觉得每次输入pnpm相关命令麻烦的同学,可以根据不同操作系统进行设置:

  • Mac或Linux系统:可以借助如zsh一类的终端工具,设置常量。例如,设置alias pnpmrs='pnpm --filter=module-a' ,使用前先执行source ~/.zshrc让设置生效。也可以进一步简化,如alias p=pnpm ,alias pr='pnpm -r exec' 。若需要传参,可以编写函数,例如:
    pa() { 
        pnpm "$1" --filter="$2" 
    } 
    
  • Windows系统:在PowerShell中,配置存放在profile.ps1文件里。可以使用Set-Alias命令设置别名,例如Set-Alias p pnpm ,Set-Alias pr 'pnpm -r exec' 。设置完成后,保存并重新加载配置文件即可使用简化后的命令。

PNPM与Yarn对比

  • Yarn的优缺点
    • 优点:相对成熟和稳定,较早支持monorepo方式,社区支持相对广泛,支持并行下载。
    • 缺点:空间占用比PNPM大,某些情况下安装性能不如PNPM,配置命令没有PNPM方便。配置workspace时,需要在package.json里写包名,相对麻烦。
  • PNPM的优缺点
    • 优点:具有高效的存储方式,性能比Yarn优越,有更严格的包命名策略。
    • 缺点:社区支持和资源没有Yarn完善,可能会遇到与项目或工具的兼容性问题,例如低版本的Node。
微前端与Monorepo的架构设计 本文主要介绍如何使 Monorepo 与微前端结合使用,篇幅较长,请结合目录酌情阅读。微前端/Monorepo方案都存在很多争议,争论无意义,选择适合自己团队的方案即可。技术实战以 Micro App + pnpm 技术栈,讲解了从零搭建到项目部署的一个完整微前端项目。 阅读详情

相关推荐

手写 Element Plus:用Monorepo架构搭建Element Plus

本文介绍了 Element Plus 源码项目的目录结构及开发环境搭建,重点阐述了使用 pnpm 的 monorepo 管理模块化代码的优势和具体实现方法。通过配置 pnpm-workspace.yaml 和分层管理 TypeScript 配置文件,实现了组件库的低耦合和高效编译。此外,涵盖了幽灵依赖问题的原理及解决方案,指导从零搭建 Element Plus 项目,细化了组件、文档和测试目录结构。

m0_63752950的博客 1498

完美搭配,微前端与 Monorepo 的架构设计

前言本文主要介绍如何使 Monorepo 与微前端结合使用,篇幅较长,请结合目录酌情阅读。微前端/Monorepo方案都存在很多争议,争论无意义,选择适合自己团队的方案即可。技术实战以 Micro App + pnpm 技术栈,讲解了从零搭建到项目部署的一个完整微前端项目。了解 Monorepo 与微前端当想使用一项新的技术时,大量的重构工作会让你不得不放弃使用新技术的想法时,这时选择微前端方案,...

React_Community的博客 2541

React Native代码共享:Monorepo项目管理策略

在当今的软件开发中,React Native已经成为构建跨平台移动应用的热门选择。随着项目的不断发展,多个React Native应用可能会有大量的代码重复,这不仅增加了维护成本,还容易导致代码不一致的问题。本文章的目的在于探讨如何通过Monorepo项目管理策略来实现React Native代码的有效共享,减少代码冗余,提高开发效率和代码质量。本文的范围涵盖了React Native和Monorepo的基本概念,核心算法原理,实际项目中的应用,以及相关工具和资源的推荐等方面。

移动开发前沿的博客 1318

没有那么难!10 分钟带你构建monorepo架构,前端通用自动化 CI/CD 方案

点击上方前端Q,关注公众号回复加群,加入前端Q技术交流群今天我们主要讨论3方面内容:如何搭建比较高效好用的monorepo工程前端如何基于搭建的monorepo工程实现自定义cli工具普通前端项目以及monorepo工程项目自动化cicd核心问题以及解决方案基于 pnpm-workspace + Turborepo + lerna 搭建 monorepo 的 cli 工程首先利用 pnpm 初始...

LuckyWinty的博客 1490

Monorepo 前端项目管理模式

Monorepo 是一种将多个项目存储在一个代码库中的策略,这使得跨项目共享和管理代码变得更加容易。在 Monorepo 模式下,所有相关的项目和组件都被存储在一个统一的代码仓库中,而不是分散在多个独立的代码仓库中。pnpm 是一个高效的包管理器,它通过使用硬链接和符号链接将包存储在共享的内容寻址存储中,从而避免了重复下载和安装。pnpm 的主要优势在于其节省磁盘空间和提高安装速度的能力。

2301_76380626的博客 1496

Monorepo与pnpm:前端项目管理的完美搭档

pnpm又称 performant npm,翻译过来就是高性能的npm。Monorepo 是一种项目开发与管理的策略模式,它代表"单一代码仓库"(Monolithic Repository)。在 Monorepo 模式中,所有相关的项目和组件都被存储在一个统一的代码仓库中,而不是分散在多个独立的代码仓库中,这些项目之间还可能会有依赖关系。npm、yarn、pnpm 等是用来管理项目依赖、发布包、安装依赖的工具,它们都提供了对工作区(workspace)的支持,允许在单个代码库中管理多个项目或包。

weixin_50367873的博客 2142

Monorepo架构: 项目管理模式对比与考量

这篇文章探讨了三种项目管理模式:单体应用(monolithic)、多仓库(multirepo)和monorepo。单体应用适合小型项目但耦合度高;多仓库便于模块复用但管理复杂;monorepo在单一仓库管理多个模块,平衡了代码复用与维护成本。文章以Vue项目为例说明模块划分标准,并介绍使用GitHub Actions统计代码量来评估项目复杂度。最后指出monorepo是当前热门的前端项目管理方案,适合中等规模项目。

Wang的专栏 1333

盘点军工行业软件研发的那些常用GJB标准

GJB5000、2786、438、141、102、8114等...

文章主要涉及嵌入式软件开发、测试、项目管理等,欢迎交流,共同进步。 9482

Monorepo,大型前端项目管理模式实践

阅读本文您将了解到:什么是 monorepo、为什么要 monorepo、如何实践 monorepo。项目管理模式Monorepo 这个词您可能不是首次听说,在当下大型前端项目中基于 monorepo 的解决方案已经深入人心,无论是比如 Google、Facebook,社区内部知名的开源项目 Babel、Vue-next ,还是集团中 rax-components 等等,都使用了 monorepo...

淘系技术 4775

Vue 10分钟入门VR全景显示 基于photo-sphere-viewer

文章目录前言一、引入photo-sphere-viewer?二、使用步骤1.引入库2.声明容器3.内容加载4.全部代码总结 前言 由于工作的需求,要实现全景图片的展示与预览,本来以为会是一个很难的内容,没想到使用现成的组件photo-sphere-viewer就可以轻松实现,上手只需要10分钟! 一、引入photo-sphere-viewer? 可以直接通过npm进行引入 npm install photo-sphere-viewer 二、使用步骤 1.引入库 photo-sphere-viewer

YIGE_MO的博客 5867

【Telephony】APN配置及加载流程&项目实践(AOSP)

学习APN关键是学会明白apns-conf.xml文件各个参数的意思,然后熟悉TelephonyProvider是如何读取文件创建数据库的,譬如数据库表的约束、文件的读写顺序等,还有读取后的ApnSetting的二次定制以及显示(例如屏蔽xcap等)。虽然一般在项目中APN的需求很简单,就是按照客户提供的APN参数添加上配置,或者在显示屏蔽一些参数,但是项目维护的过程中APN的问题也是比较多的。

weixin_44513784的博客 5515

Monorepo 与包管理工具:从幽灵依赖看 npm 与 pnpm 的架构差异

Monorepo是一种将多个项目集中管理的代码仓库模式,具有代码共享、统一依赖管理、原子化提交等优势,适合微前端和关联项目开发。相比Multirepo,Monorepo简化了依赖管理但增加了仓库体积。在工具选择上,pnpm比npm更高效,能避免"幽灵依赖"问题——即未声明却可使用的间接依赖包,这种依赖可能引发版本冲突和安全风险。建议新项目使用pnpm进行严格依赖隔离,定期用depcheck工具检测幽灵依赖。

用于分享前端相关的知识和架构体系 1475

我对 monorepo 的一些思考

最近在自己的新项目中,使用了模板,并不断地做了不少改进。在此,我想借此机会分享一下这个模板的演变过程,以及我对monorepo的一些思考。强大的monorepo管理 (pnpmturborepo单元测试 (vitest包括cli bin全部都是typescript代码规范与质量 (eslintgit提交规范 (huskycommitlintpnpm部署Docker模板自动发布npm包 (changeset配置文件同步升级默认把repo放在packages和apps这2个目录里面从单仓到。

ice breaker's blog 1444

Star CCM+中衍生零部件下的阈值应用与区域内删除目标网格

同样的在绘制网格结束后,有时出现负体积网格或质量差的网格,为了节约时间成本,可能会选择将负体积的网格或质量差的网格删除。弹出相应的窗口,在窗口中选择相应的区域①,选择标量函数②(此处以网格体积变化为例),选择模型③,设置阈值④,选择No Dispalyer,会根据需求选择显示,最后点击Create⑥完成创建。此处以温度为例,若出现温度异常点,首先在①栏中勾选Function,然后在下面点击⑤Select,在弹出的Function窗口中选择温度场函数,再点击④Identify,查找温度异常网格数量。

2201_75375391的博客 2222

[南大ICS-PA2] 字符串处理函数和printf实现

[南大ICS-PA2] 程序、运行时环境与AM 字符串处理函数和printf实现

qq_42474104的博客 2987

Monorepo 详解:现代前端工程的架构革命

Monorepo是现代软件开发中管理多项目代码的有效策略。它将多个项目的代码集中存放在单一仓库中,具有统一依赖管理、原子性提交、代码共享等优势,被Google等大型科技公司广泛采用。文章详细介绍了Monorepo的概念,对比了其与Multirepo的区别,并分析了实施中面临的构建效率、权限管理等挑战。同时推荐了Lerna、Nx等主流Monorepo管理工具,并通过一个基于Yarn Workspaces的React+Node.js项目示例,展示了Monorepo的实际应用。该策略特别适合大型项目和多团队协作场

警警的博客 2733

8、水力压裂引起的地质材料力学性质变化的可视化研究

本研究探讨了水力压裂引起的地质材料力学性质变化的可视化方法。利用超声剪切波形数据,通过短时傅里叶变换(STFT)和主成分分析(PCA)进行特征提取和降维,并应用K-means聚类、凝聚聚类和DBSCAN等无监督学习方法对地质力学变化进行非侵入式可视化分析。研究比较了不同特征工程、聚类方法和降维策略对可视化效果的影响,并结合位移不连续性理论为聚类结果分配地质力学变化指数,以提高结果的物理解释性。最终,该方法成功实现了对水力压裂引起的岩石力学性质变化的高效、可靠可视化。

emacs5lisp的博客 109

monorepo架构设计方案

核心特征:多个相关项目/包存储在同一个代码仓库中本质:工程化架构方案,解决多项目管理问题对比:传统 Multirepo(多仓库) vs Monorepo(单仓库)

棉花没有糖的博客 1557

【stata基础代码大全 】 可独立完成一篇实证

用stata打开,直接替换自己需要的变量就行,小白友好❗️❗️❗️。八、八.中介效应检验:路径分析(三种方法)第二种方法即Sobel-Goodman检验。*(7)Winsor处理,剔除异常值。六、内生性问题解决方法(附具体模型)其三,工具变量:两阶段最小二乘。第三种方法即Bootstrap检验。二、Stata中数据的基本处理。*(5)生成行业、年度虚拟变量。PSM1————近邻匹配。七、调节效应检验:机制分析。*(2)剔除数据中的样本。*(4)给变量添加标签。*(3)生成新的变量。*(6)基本数据匹配。

J_Giser的博客 8025

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

上一篇: Monorepo架构: 项目管理模式对比与考量
下一篇: Monorepo架构: Lerna、NX、Turbo等对比与应用分析
Wang's Blog
博客等级 码龄12年 7434粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值