Monorepo设置:新手指南

news2025/1/13 9:28:58

Monorepo是一种项目代码管理方法,指在单个代码仓库中管理多个项目,有助于简化代码共享、版本控制、构建和部署的复杂性,并提供更好的可重用性和协作性。

简单理解:所有项目都在一个代码仓库中 📦,但这并不意味着所有代码都组织在一个文件夹中 🗂️。 事实上,一个好的Monorepo与单体代码库恰恰相反;它应该结构良好且模块化。

2f0761948047def34f6f865a91a6cee9.png

发展历程

单体时期

单一代码仓库:传统的单体应用程序通常将所有功能和模块打包在一起,形成单一的代码库和部署单元。这个单一代码库包含应用程序的所有部分,从前端界面到后端逻辑,甚至包括数据库架构和配置文件。

问题:

  • 难以实现局部更新和独立扩展的灵活性 🛠️

  • 高度耦合,代码臃肿 🧩

MultiRepo时代

多个代码仓库:不同的功能模块、组件或服务存储在独立的仓库中,可以独立进行版本控制、构建、部署和发布,使不同的团队或开发者能够独立开发、测试和维护自己的模块,更容易实现并行开发和团队协作。

问题:

  • 跨仓库开发:多仓库维护成本高

  • 开发调试:npm包(修改->发布->安装成本高),调试麻烦 🐛

  • 版本管理:依赖版本同步和升级管理麻烦

  • 项目基建:脚手架升级难以保证新老项目规范统一 🏗️

MonoRepo时代

随着业务复杂度增加,模块仓库越来越多。虽然MultiRepo在业务上解耦,但增加了项目工程管理的难度。当模块仓库达到一定程度时,会出现以下几个问题:

  • 跨仓库代码难以共享

  • 单一仓库中模块依赖管理分散复杂

  • 构建时间增加

因此,将多个项目整合到一个仓库中,共享项目配置,快速共享模块代码,已成为一种趋势。

Monorepo的优势

  • 代码复用:因为多个项目共享一个代码库,避免了在不同项目中重复编写相同功能代码的问题,提高开发效率。

  • 提高协作效率:多个项目在同一个代码库中开发,可以方便地共享代码和文档,避免了不同项目之间的沟通和协调成本。

  • 集中管理:在Monorepo架构中,不同的应用程序都在同一个代码库中,便于管理和监控。这一点很重要,特别是在需要同时修改和维护多个版本时。

  • 统一构建:Monorepo的一个重要特征是可以共享一套构建系统和工具链进行构建和部署,提高了构建效率。

  • 问题可以快速定位:由于所有代码都在同一个代码库中开发,调试器可以快速找到问题所在的代码文件和行号,方便开发人员调试问题。

  • 一个版本:不用担心你的项目依赖冲突版本的第三方库而导致不兼容。

Monorepo的陷阱

幻影依赖

当npm/yarn安装依赖时,存在依赖提升。一个项目使用的依赖即使没有在其package.json中声明也可以直接使用。 这种现象称为"幻影依赖"。随着项目迭代,这个依赖不再被其他项目使用而不再安装。使用幻影依赖的项目会因为找不到依赖而报错 😤。 基于npm/yarn的Monorepo方案仍然存在"幻影依赖"问题。我们可以通过pnpm完全解决这个问题

依赖安装耗时长

MonoRepo中的每个项目都有自己的package.json依赖列表。随着MonoRepo总依赖数量增长,每次install都会耗费更长时间 😭。 相同版本的依赖会提升到Monorepo根目录,以减少重复依赖安装。所以使用pnpm进行按需安装和依赖缓存

Pnpm包管理

为什么选择pnpm?

Monorepo单仓库模块划分的需求要求仓库中的模块不仅要处理与外部模块的关系,还要处理内部依赖。因此,我们需要选择一个强大的包管理工具来帮助处理这些任务。 2022年后,我们推荐使用pnpm来管理项目依赖。它pnpm涵盖了大部分的能力,并在多个维度上大大提升了体验 💯。

Monorepo环境搭建

通过以上内容,我们了解了Monorepo的优势以及选择pnpm的原因。 那么如何搭建Monorepo呢? 接下来,让我们通过Element Plus来学习如何搭建Monorepo环境 🤝

首先全局安装pnpm

npm install pnpm -g

然后使用pnpm init在项目中初始化package.json。这与npm init相同。

pnpm init

获取package.json的初始内容,然后删除package.json中的name属性并添加"private": true属性,因为它不需要发布。

{
  "private": true,
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

配置pnpm的monorepo工作空间

在我们的仓库中,我们需要管理多个项目,所以我们可以使用pnpm的monorepo。我们在仓库根目录创建一个pnpm-workspace.yaml文件,我们可以在pnpm-workspace.yaml配置文件中指定仓库中有多少个项目。

packages:
- play # 存放组件测试代码
- docs # 存放组件文档
- packages/* # packages目录下的所有包都是组件包

在packages目录中,我们可以放置很多package项目目录,如组件包目录:

  • components

  • 主题包目录:theme-chalk

  • 工具包目录:utils等

然后每个包目录也需要一个package.json文件来声明这是一个NPM包目录。所以我们需要进入每个包目录初始化一个package.json文件。

以components包为例,我们进入components目录,初始化一个package.json文件,并更改包名:@elemnet-plus/components。文件内容如下:

{
  "name": "@elemnet-plus/components",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

其他两个包分别命名为@elemnet-plus/theme-chalk@elemnet-plus/utils,创建过程与上述相同。

到目前为止,我们初步的项目目录结构如下:

├── README.md
├── package.json
├── packages
│   ├── components
│   │   └── package.json
│   ├── theme-chalk
│   │   └── package.json
│   └── utils
│       └── package.json
├── play
└── pnpm-workspace.yaml

仓库项目包之间相互调用

如果这些包要相互调用,需要将@elemnet-plus/components@elemnet-plus/theme-chalk@elemnet-plus/utils安装到仓库根目录下的node_modules目录中。

然后我们在根目录中安装:

pnpm install @elemnet-plus/components -w
pnpm install @elemnet-plus/theme-chalk -w
pnpm install @elemnet-plus/utils -w

-w表示安装到公共模块packages.json中,即根目录的packages.json中。

安装后根目录的package.json内容为:

{
  "dependencies": {
    "@elemnet-plus/components": "workspace:*",
    "@elemnet-plus/theme-chalk": "workspace:*",
    "@elemnet-plus/utils": "workspace:*"
  },
}

注意:workspace:*这个在将来发布时会被转换成具体的版本号。

总结

至此,一个通过pnpm配置的monorepo基础环境已经搭建完成。

什么才是真正的工程化。在配置这个开发环境的过程中,我们似乎只是用一堆工具进行各种配置,那是不是意味着前端工程化就是工具化呢?

实际上,它不仅仅是工具。工程化注重使用工具作为手段来规范工作流程——表达思想、规范项目、有效管理编写代码的团队。

最后:

React Hook 深入浅出

CSS技巧与案例详解

vue2与vue3技巧合集

VueUse源码解读

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

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

相关文章

[Python学习日记-75] 计算机基础与网络

[Python学习日记-75] 计算机基础与网络 简介 计算机基础 什么是网络编程 计算机网络 简介 本篇主要介绍的计算机基础是浓缩的,这是因为我们主要学习的是 Python,而 Python 主要是为了开发应用程序的,并不会用它来开发操作系统和嵌入式程序…

1. Doris分布式环境搭建

一. 环境准备 本次测试集群采用3台机器hadoop1、hadoop2、hadoop3, Frontend和Backend部署在同一台机器上,Frontend部署3台组成高可用,Backend部署3个节点,组成3副本存储。 主机IP操作系统FrontendBackendhadoop1192.168.47.128Centos7Foll…

【Java】-- 利用 jar 命令将配置文件添加到 jar 中

目录 1、准备 2、目标 3、步骤 3.1、安装 jdk 3.2、添加配置文件 3.3、校验 1、准备 java 环境hadoop-core-1.2.1.jar 和 core-site.xml 2、目标 将 core-site.xml 添加到 hadoop-core-1.2.1.jar 中。 3、步骤 3.1、安装 jdk 3.2、添加配置文件 jar -cvf hadoop-core-…

day14-Linux系统基础权限知识精讲

1. 给文件加特殊属性 1.1 chattr a:只能追加内容,不能删除 i:不能修改,不能删除;保护关键文件,防止非法写入 [rootoldboy ~]# chattr a test.txt [rootoldboy ~]# chattr i test.txt [rootoldboy ~]# echo 123 >> test.txt -bash: t…

Android使用系统消息与定时器实现霓虹灯效果

演示效果: 界面设计: 在帧布局FrameLayout中添加6个TextView 依次设置这6个TextView的宽,高,权重 也可在XML中直接设置 添加自定义颜色 关联自定义颜色到数组变量 关联6个TextView控件到数组变量 处理自定义系统消息 Handler _sysHandler new Han…

数据结构大作业——家谱管理系统(超详细!完整代码!)

目录 设计思路: 一、项目背景 二、功能分析 查询功能流程图: 管理功能流程图: 三、设计 四、实现 代码实现: 头文件 结构体 函数声明及定义 创建家谱树头结点 绘制家谱树(打印) 建立右兄弟…

vue3+elementPlus之后台管理系统(从0到1)(day1)

vue3官方文档:https://cn.vuejs.org/guide/introduction.html 1、项目创建 确保电脑已安装node 查看命令: node -v进入项目目录,创建项目 npm init vuelatest Need to install the following packages: create-vue3.13.0 Ok to procee…

汉图科技XP356DNL高速激光打印一体机综合性能测评

汉图科技XP356DNL高速激光打印一体机效率方面表现出色,支持A4纸型的高速打印,单面打印速度高达35页/分钟,自动双面打印速度可达32面/分钟,这样的速度在日常办公中能够极大地提高打印效率,减少等待时间,满足…

【芯片封测学习专栏 -- 什么是 Chiplet 技术】

请阅读【嵌入式开发学习必备专栏 Cache | MMU | AMBA BUS | CoreSight | Trace32 | CoreLink | ARM GCC | CSH】 文章目录 OverviewChiplet 背景UCIeChiplet 的挑战 Overview Chiplet 又称为小芯片。该技术通过将大型SoC划分为更小的芯片,使得每个部分都能采用不同…

1.CSS的复合选择器

1.1 什么是复合选择器 在CSS中,可以根据选择器的类型把选择器分为基础选择器和复合选择器,复合选择器是建立在基础选择器之上,对基础选择器进行组合形成的。 复合选择器可以更精准、更高效的选择目标元素(标签) 复…

【MySQL】SQL菜鸟教程(一)

1.常见命令 1.1 总览 命令作用SELECT从数据库中提取数据UPDATE更新数据库中的数据DELETE从数据库中删除数据INSERT INTO向数据库中插入新数据CREATE DATABASE创建新数据库ALTER DATABASE修改数据库CREATE TABLE创建新表ALTER TABLE变更数据表DROP TABLE删除表CREATE INDEX创建…

docker 自建rustdesk服务器测试

参考https://blog.csdn.net/tootsy_you/article/details/130010564 注意: docker-compose.yml version: 3networks:rustdesk-net:external: falseservices:hbbs:container_name: hbbsports:- 21115:21115- 21116:21116- 21116:21116/udp- 21118:21118image: rust…

检验统计量与p值笔记

一、背景 以雨量数据为例,当获得一个站点一年的日雨量数据后,我们需要估计该站点的雨量的概率分布情况,因此我们利用有参估计的方式如极大似然法估计得到了假定该随机变量服从某一分布的参数,从而得到该站点的概率密度函数&#x…

每日十题八股-2025年1月12日

1.为什么四次挥手之后要等2MSL? 2.服务端出现大量的timewait有哪些原因? 3.TCP和UDP区别是什么? 4.TCP为什么可靠传输 5.怎么用udp实现http? 6.tcp粘包怎么解决? 7.TCP的拥塞控制介绍一下? 8.描述一下打开百度首页后发生的网络过…

制造企业“数字化转型”典型场景参考

聚焦产业链上下游企业研发设计、生产制造、运维服务、经营管理、供应链管理等场景,以场景为切入点梳理数字化转型痛点需求,绘制重点行业、重点产业链数字化转型场景图谱(简称“一图谱”),明确企业数字化转型路径&#…

Web渗透测试之XSS跨站脚本 防御[WAF]绕过手法

目录 XSS防御绕过汇总 参考这篇文章绕过 XSS payload XSS防御绕过汇总 服务端知道有网络攻击或者xss攻 Html

《机器学习》——sklearn库中CountVectorizer方法(词频矩阵)

CountVectorizer方法介绍 CountVectorizer 是 scikit-learn 库中的一个工具,它主要用于将文本数据转换为词频矩阵,而不是传统意义上的词向量转换,但可以作为词向量转换的一种基础形式。用于将文本数据转换为词频矩阵,它是文本特征…

session-manager-plugin: command not found 解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Linux之读者写者模型与特殊锁的学习

目录 读者写者模型 特殊锁 悲观锁 自旋锁 在前几期,我们学习了多线程的生产者和消费者模型,生产者和消费者模型中,有三种关系,两个角色,一个场所,那么读者写者模型和生产者消费者模型有什么关联吗&…

期刊(中英),期刊分区,期刊所在数据库(中英),出版商区别和联系

目录 对期刊、分区、数据库、出版商整体了解期刊(中英)期刊分区期刊所在数据库总结 出版商 对期刊、分区、数据库、出版商整体了解 下图是我对这四部分的一个理解,其中期刊根据论文使用语言分为中英两种,期刊分区是用来评判论文质…