vue3 + pnpm 打造一个 monorepo 项目
Monorepo 和 Multirepo
单一仓库(Monorepo)架构,可以理解为:利用单一仓库来管理多个packages的一种策略或手段;与其相对的是多仓库(Multirepo)架构
Monorepo 目录中除了会有公共的package.json依赖以外,在每个sub-package子包下面,也会有其特有的package.json依赖。
兄弟模块之间可以通过模块 package.json 定义的 name 相互引用,保证模块之间的独立性
# monorepo目录结构
monorepo-demo
├── packages
│ ├─ module-a
│ │ ├─ src # 模块 a 的源码
│ │ ├─ node_modules # 模块 a 的 node_modules
│ │ └─ package.json # 仅模块 a 的依赖
│ └─ module-b
│ ├─ src # 模块 b 的源码
│ └─ package.json # 仅模块 b 的依赖
├── .eslintrc # 配置文件,对整个项目生效
├── node_modules # 所有子包公共的 node_modules
└── package.json # 所有子包公共的依赖
Multirepo 更倾向与在项目制中,将一个个项目使用不同的仓库进行隔离,每一个项目下使用独有的package.json来管理依赖
# multirepo-a目录结构
multirepo-a
├── src
├── .eslintrc
├── node_modules
└── package.json
# multirepo-b目录结构
multirepo-b
├── src
├── .eslintrc
├── node_modules
└── package.json
Monorepo 工具
在采用 Monorepo(单一仓库)架构的软件开发中,工具的选择是至关重要的。合适的 Monorepo 工具能够帮助团队更高效地管理大规模代码库、提升协同开发体验以及优化构建和部署流程。
直至 2024 年,目前在前端界比较流行的 Monorepo 工具有 Pnpm Workspaces、Yarn Workspaces、npm Workspaces、Rush、
Turborepo、Lerna、Yalc、和 Nx
强烈推荐使用Pnpm Workspaces 作为 Monorepo 项目的依赖管理工具
那么 Monorepo 与包管理工具(npm、yarn、pnpm)之间是一种怎样的关系?
这些包管理工具与 monorepo 的关系在于,它们可以为 monorepo 提供依赖安装与依赖管理的支持,借助自身对 workspace 的支持,允许在 monorepo 中的不同子项目之间共享依赖项,并提供一种管理这些共享依赖项的方式,这可以简化依赖项管理和构建过程,并提高开发效率。
Monorepo 项目搭建
背景
传统的多仓库 Multirepo 模式,通常都是一个仓库存放一个项目。比如现在你有三个项目,就需要创建三个远程仓库,并且需要为每个项目单独安装和升级依赖
而单一仓库 Monorepo 模式,就是在一个仓库中管理多个项目,这些项目可以是独立的,也可以相互依赖。通过 Monorepo,多个项目可以共享依赖。比如多个项目都需要 lodash,那我们也只需安装一次即可
pnpm i lodash -w
当然,Monorepo 中除了公共的package.json依赖以外,在每个sub-package子包下面,也会有其私有的package.json依赖
我们本次选择Pnpm Workspaces 作为 Monorepo 项目的依赖管理工具,一起来搭建一个 monorepo 项目
安装包管理工具
全局安装 pnpm
npm i pnpm -g
初始化项目
创建一个新的项目目录 pnpm-monorepo,根目录运行 pnpm init 创建 package.json 文件
然后根目录新建一个文件夹 packages,用于存储子包
新建 packages/libc-shared( 共享包 ),用于存放多个项目或组件之间共享的代码 。运行 pnpm init 创建 package.json 文件,修改 package.json 的 name 为 "@libc/shared";修改 package.json 的 main 入口文件路径字段为"src/index.js"
{
"name": "@libc/shared",
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
}
新建 packages/libc-ui( 公共组件包 ),即UI组件库,这里我们直接 clone 了 iview-ui-plus 代码。运行 pnpm install 安装依赖,
修改 package.json 的 name 为 "@libc/ui";修改 package.json 的 main 入口文件路径字段为"src/index.js"
然后我们在 packages 下创建两个 vue 项目,vue-dom1 和 vue-dom2,运行脚本pnpm create vue@latest。由于两个项目的依赖是完全一样的,我们可以将 dependencies、devDependencies 复制到外层 package.json 中当做公共依赖,然后pnpm install 安装一次即可
到了这一步,vue 项目还是不能运行,必须要先配置 workspace,用于支持多包存储库让子包 vue 项目可以访问到我们的公共依赖
配置workspace
根目录新建一个 pnpm-workspace.yaml,将 packages 下所有的目录都作为包进行管理
packages:
# all packages in direct subdirs of packages/
- 'packages/*'
pnpm-monorepo 最终项目结构
pnpm-monorepo/
├── packages/
│ ├── libc-shared/
│ ├── libc-ui/
│ ├── vue-dome1/
│ └── vue-dome2/
├── package.json
└── pnpm-workspace.yaml
子包共享
此时,pnpm-workspace.yaml工作空间下的每个子包都可以共享我们的公共依赖了。还有个问题是,兄弟模块之间如何共享呢?
之前我们说过,子包之间可以通过 package.json 定义的 name 相互引用,一起看下两个实际场景
- 如何把子包 libc-shared 共享出去?
用--workspace参数去安装共享子包,会去 workspace工作空间中找依赖项并安装
pnpm install @libc/shared --workspace -w
package.json 中就会自动添加如下依赖,"workspace:" 只会解析本地 workspace 包含的 package
"dependencies": {
"@libc/shared": "workspace:^"
}
此时,vue 项目就可以使用公共包 libc-shared 里的方法,import 引入即可
import { isObject } from '@libc/shared'
- 如何把子包 libc-ui 共享出去?
重复一下上面的步骤,然后我们去引用一个 button组件,发现报错了 Failed to resolve import "./base" from "../libc-ui/src/components/typography/title.vue". Does the file exist?
vite.config.js 中添加 extensions 即可解决,配置一下省略的扩展名列表
resolve: {
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
}
虽然 button 组件引用成功了,但是发现没有任何样式效果。在 libc-ui/src/index.js 文件中导入一下样式文件就行了
import "./styles/index.less";
依赖
公共依赖
全局安装公共依赖 lodash。需要加-w(在工作空间的根目录中启动 pnpm)
pnpm install lodash -w
这样,vue-dom1 和 vue-dom2 这两个 vue项目就都可以使用 lodash 库了
局部依赖
如果只有 vue-dom1 项目用到了 lodash,我们也可以安装到 vue-dom1 项目内部,不作为公共依赖项,有两种方法可以实现
- cd 到 src/packages/vue-dom1 目录下,直接安装
pnpm install lodash
- 在任意目录下,使用
--filter参数进行安装;package_selector:package.json 对应的 name 字段
pnpm install lodash --filter <package_selector>
shamefully-hoist
shamefully-hoist,默认 false
false:
node_modules下只能看到直接依赖的套件,次级依赖在node_modules/.pnpm目录下;无法访问其他子包局部安装的依赖项,例如,vue-dome2 安装的 lodash,vue-dome1 是访问不到的true:將所有套件都拉升到
node_modules目錄下,能访问到其他子包局部安装的依赖项,例如,vue-dome2 安装的 lodash,vue-dome1 是能访问到的
// .npmrc
# pnpm 配置
shamefully-hoist=false
配套代码
GitHub - burc-li/pnpm-monorepo: vue3 + pnpm + monorepo 项目 demo
参考文档
突破项目瓶颈:2024 年 Monorepo 工具选择和实践 | BEEZEN
GitHub - Tyh2001/vue3-pnpm-monorepo: vue3 + pnpm + monorepo 项目 demo
vue3 + pnpm 打造一个 monorepo 项目的更多相关文章
- 从0搭建Vue3组件库(二):Monorepo项目搭建
本篇文章是从0搭建Vue3组件库系列文章第二篇,本篇文章将带领大家使用pnpm搭建一个简单的Monorepo项目,并完成包的关联与测试 什么是 Monorepo 其实很简单,就是一个代码库里包含很多的 ...
- 【源码项目+解析】C语言/C++开发,打造一个小项目扫雷小游戏!
一直说写个几百行的小项目,于是我写了一个控制台的扫雷,没有想到精简完了代码才200行左右,不过考虑到这是我精简过后的,浓缩才是精华嘛,我就发出来大家一起学习啦,看到程序跑起来能玩,感觉还是蛮有成就感的 ...
- 【前端vue进阶实战】:从零打造一个流程图、拓扑图项目【Nuxt.js + Element + Vuex】 (一)
本系列教程是用Vue.js + Nuxt.js + Element + Vuex + 开源js绘图库,打造一个属于自己的在线绘图软件,最终效果:topology.le5le.com .如果你觉得好,欢 ...
- 打造一个高逼格的android开源项目——小白全攻略 (转)
转自:打造一个高逼格的android开源项目 小引子 在平时的开发过程中,我们经常会查阅很多的资料,最常参考的是 github 的开源项目.通常在项目的主页面能看到项目的简介和基本使用,并且时不时能看 ...
- 如何打造一个"逼格"的web前端项目
最近利用空余的时间(坐公交车看教程视频),重新了解了前后端分离,前端工程化等概念学习,思考如何打造一个“逼格”的web前端项目. 前端准备篇 前端代码规范:制定前端开发代码规范文档. PS:重中之中, ...
- 微人事 star 数超 10k,如何打造一个 star 数超 10k 的开源项目
看了下,微人事(https://github.com/lenve/vhr)项目 star 数超 10k 啦,松哥第一个 star 数过万的开源项目就这样诞生了. 两年前差不多就是现在这个时候,松哥所在 ...
- 【前端新手也能做大项目】:跟我一起,从零打造一个属于自己的在线Visio项目实战【ReactJS + UmiJS + DvaJS】(二)
本系列教程是教大家如何根据开源js绘图库,打造一个属于自己的在线绘图软件.当然,也可以看着是这个绘图库的开发教程.如果你觉得好,欢迎点个赞,让我们更有动力去做好! 本系列教程重点介绍如何开发自己的绘图 ...
- Qt 新手实战项目之手把手打造一个串口助手
一前景 很多时候我们在学习一门新的语言,一直在学习各种语法和记住各种关键字,很容易产生枯燥的情绪,感觉学习这些玩意儿不知道用在什么地方,心里很是苦恼,这不,我在这记录下我学习Qt的第一个的小项目-串口 ...
- 基于 Lerna 管理 packages 的 Monorepo 项目最佳实践
本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/NlOn7er0ixY1HO40dq5Gag作者:孔垂亮 目录 一.背景二.Monorepo vs M ...
- [后端人员耍前端系列]AngularJs篇:使用AngularJs打造一个简易权限系统
一.引言 上一篇博文已经向大家介绍了AngularJS核心的一些知识点,在这篇博文将介绍如何把AngularJs应用到实际项目中.本篇博文将使用AngularJS来打造一个简易的权限管理系统.下面不多 ...
随机推荐
- 【JS设计模式笔记】-观察者模式(即发布-订阅模式)(结构型)
发布-订阅模式的作用 比如常见的发送短信就是一个典型的发布-订阅模式,例如,小明.小红去售楼处购买房子,但是售楼处的工作人员告诉小明.小红当前楼盘已经售罄,新楼盘还没有开售,这个时候,小明.小红把自己 ...
- 1Panel:一个现代化、开源的 Linux 服务器运维管理面板
前言 之前有小伙伴问:Linux 服务器运维管理除了宝塔,还有其他值得推荐的管理软件吗?,今天大姚给大家分享一个现代化.开源的 Linux 服务器运维管理面板:1Panel. 项目介绍 1Panel是 ...
- [TK] BLO
初步分析 此题描述让我们想到Tarjan求割点,因此我们从割点的角度来探讨一下这道题. 假如我们去掉的不是一个割点,那么它实际上不会对连通性造成影响,但是根据样例可以看出来,删去这个点导致了其余点与当 ...
- SpringBoot+Docker +Nginx 部署前后端项目
部署SpringBoot项目(通关版) 一.概述 使用 java -jar 命令直接部署项目的JAR包和使用Docker制作镜像进行部署是两种常见的部署方式.以下是对这两种方式的概述和简要的优劣势分析 ...
- constexpr声明 常量表达式
constexpr 是 C++ 中用于声明 常量表达式 的关键字,表示一个变量或函数的值在编译时就可以确定,而不是在运行时计算. 这对优化非常有用,因为编译器可以直接将结果嵌入到程序中,减少运行时 ...
- linux 挂载硬盘报错 "mount: unknown filesystem type 'ntfs'"
这个错误是说,系统无法识别ntfs格式的硬盘.所以不能直接挂载. 解决这个问题的思路有两个: 格式化磁盘为linux可以识别的格式. 通过工具使linux可以识别ntfs格式. 如果是第一次挂载硬盘可 ...
- HRM平台的登录页的背景图片- scss
.login-container { // 设置背景图片 background-image: url("~@/assets/common/login.jpg"); ba ...
- Spring 实现 3 种异步流式接口,干掉接口超时烦恼
大家好,我是小富- 如何处理比较耗时的接口? 这题我熟,直接上异步接口,使用 Callable.WebAsyncTask 和 DeferredResult.CompletableFuture等均可实现 ...
- Kubernetes 持久化存储之 NFS 终极实战指南
作者:运维有术星主 在 Kubernetes 生态系统中,持久化存储扮演着至关重要的角色,它是支撑应用稳定运行的基石.对于那些选择自建 Kubernetes 集群的运维架构师而言,选择合适的后端持久化 ...
- Minecraft小说
小说标题:<方块与冒险:勇者的传说> 持续更新中 故事简介: 主角艾伦(Alan)是一个普通的玩家,偶然之间被传送到Minecraft的世界中.这个世界充满了各种各样的奇迹.冒险.危险和谜 ...