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来打造一个简易的权限管理系统.下面不多 ...
随机推荐
- ZEGO 最后一公里网络传输的容灾及优化方案
作为运维,你是否遇到过一些用户域名解析异常,你是否又遇到过某些区域云商加速节点异常导致业务不可用,此时的你一脸茫然,不知所措?作为运维,你是否被最后一公里问题搞得焦头烂额? 那么今天我们就来探讨一下最 ...
- PDF解析,还能做得更好
随着大模型文档智能应用逐渐步入正轨,文档解析类产品成为其中重要的一环.文档解析工具能够"唤醒"沉睡在PDF文件中的知识,将其转化为机器能够识别.读取的信息,将可用数据从txt.cs ...
- Angular 18+ 高级教程 – Signals
前言 首先,我必须先说明清楚.Signal 目前不是 Angular 的必备知识. 你的项目不使用 Signal 也不会少了条腿,断了胳膊. Angular 官方维护的 UI 组件库 Angular ...
- Angular 18+ 高级教程 – 关于本教程
版本声明 本教程写于 Angular v17,但往后的所有新功能,API 都有更新到相关文章里头,所以教程总是最新的,大家可以安心学习. 前言 光阴飞逝,一转眼,我尽然已经有两年多的时间完全没有接触 ...
- 算法与数据结构——AVL树(平衡二叉搜索树)
AVL树 在"二叉搜索树"章节提到,在多次插入和删除操作后,二叉搜索树可能退化为链表.在这种情况下,所有操作的时间复杂度将从O(logn)劣化为O(n). 如下图,经过两次删除节点 ...
- 图书《React.js实战》代码下载
图书<React.js实战>代码下载链接:https://pan.baidu.com/s/1kep0xsTeSupyr15c3VwmBw 提取码:9pra 这个代码经过图书<Reac ...
- foobar2000 v2.1.6 汉化版
foobar2000 v2.1.6 汉化版 -----------------------[软件截图]---------------------- -----------------------[软件 ...
- MYSQL存储过程-练习5 游标
MYSQL存储过程-练习5 游标 1 DELIMITER $ 2 CREATE PROCEDURE sp_cur() 3 BEGIN 4 DECLARE bkname VARCHAR(200); 5 ...
- Android复习(五)设备兼容—>多apk支持
1. 对于不同的屏幕发布单独的apk https://developer.android.google.cn/training/multiple-apks/screensize 2.多窗口模式 在An ...
- 在 Kubernetes Pod 中如何获取客户端的真实 IP
Kubernetes 依靠 kube-proxy 组件实现 Service 的通信与负载均衡.在这个过程中,由于使用了 SNAT 对源地址进行了转换,导致 Pod 中的服务拿不到真实的客户端 IP 地 ...