NodeJS 零散小项目难管理?试试这个 npm 提供的 'monorepo' - workspace
最近写了的一些模块化,还有偏实验的文章,里面都有很多例子,大多都是提交 1
到 2
次,基本就结束整个项目的生命周期了,所以我就想着能不能把它们集中起来管理,简单搜索了一下,也许 monorepo
能解决我的问题
monorepo
Monorepo 的意思是在版本控制系统的单个代码库里包含了许多项目的代码。这些项目虽然有可能是相关的,但通常在逻辑上是独立的,并由不同的团队维护。
简单来说就是把几个项目丢到一个目录里面管理,但是这种属于‘简陋’的 monorepo
,优秀的 monorepo
通常具有依赖管理、引用一致等功能,而对于我们的 npm
来说,就提供了 workspaces
来帮助我们实现 monorepo
Workspaces
指的是npm cli
中的一组功能,它支持从单个根目录package
中管理本地文件系统中的多个package
广义的 monorepo 是可以包含 android/iOS/H5/Web 各种代码的,但是文章实现的是基于 Node.js 的狭义 monorepo
实践
我使用的 node@16.15.1 | npm@8.11.0
,支持 workspaces
并且是 LTS
版本,关于 Node.js
和 Npm
的对应关系可以参考此链接
您可以在线查看源代码
本次的 monorepo
将集成我的以下几个项目
- pandoralink/vue2-start-with-vite
- pandoralink/vue-start-with-webpack
- pandoralink/react-start-with-vite
- pandoralink/react-start-with-webpack
初始化
先初始化一个项目
npm init
无论是已经开发中或者是刚创建的 Node.js
项目都可以使用下面这个命令去开启 workspaces
npm init [options] [your_package_name]
# Options
# -w, --workspace=[your_package_name]
# Exampe
# npm init -w ./package/vue2-start-with-vite
添加的时候会走一遍类似 npm init
的流程,比如下面这种
已经有仓库的就没必要太在意初始化的 CLI
了,建议直接上默认选项,然后再复制就完事了
npm init -w ./package/your-porject-name -y
# 例如
# npm init -w ./package/react-start-with-webpack -y
添加完后会重写在项目根目录的 package.json
,加上一个 workspaces
属性
{
// ...
"workspaces": [
"package\\vue2-start-with-vite",
"package\\vue-start-with-webpack",
"package\\react-start-with-webpack",
"package\\react-start-with-vite"
],
// ...
}
项目结构如下
├── node_modules
├── package
| ├── react-start-with-vite
| ├── react-start-with-webpack
| ├── vue-start-with-webpack
| └── vue2-start-with-vite
├── package-lock.json
└── package.json
接下来就是喜闻乐见的依赖环节
添加/删除/更新依赖
worksapce
对库中某个项目的添加/删除更新依赖操作语法如下
npm [options] [dependencies_name] -w [project_name]
# Options
# install [dependencies_name]
# uninstall [dependencies_name]
# update [dependencies_name]
# Example
# npm install vue@2.7.10 -w vue2-start-with-vite
前面部分和正常的单一代码库的操作一致,使用 workspaces
的时候后缀加上 -w [project_name]
就行
也可以子项目整个下载或者整个 monorepo
一起下载
npm install
npm install -w [project_name]
依赖关系
workspaces
全部的子项目的依赖都是在 root
(根目录)的 node_modules
下统一管理的
依赖冲突
对于 monorepo
这种单一代码库来说,统一管理依赖必然会有冲突,而 npm
的 workspaces
的解决方案如下,对于进入根目录的 node_modules
的依赖会根据 workspaces
里面的顺序决定
{
// ...
"workspaces": [
"package\\vue2-start-with-vite",
"package\\vue-start-with-webpack",
"package\\react-start-with-webpack",
"package\\react-start-with-vite"
],
// ...
}
而对于依赖冲突,就比如 vue2-start-with-vite
项目里用的是 vue@2.7.10
,而 react-start-with-vite
项目里用到了 vue@3.2.45
,那么下载的时候,根目录会是 vue@2.7.10
,而子目录 react-start-with-vite
项目会开一个 node_modules
里面会下载 vue@3.2.45
,如下
├── node_modules
| ├── ...
| ├── vue@2.7.10
| └── ...
├── package
| ├── react-start-with-vite
| | ├── node_modules
| | | ├── ...
| | | ├── vue@3.2.45
| | | └── ...
| | └── package.json
| └── ...
├── package-lock.json
└── package.json
这个解决思路非常好,但是有个缺点,比如 react-start-with-vite
项目突然不需要这个 vue@3.2.45
,uninstall
以后总是会留一堆“来过的痕迹”(非常丑陋)
运行
运行命令如下
npm run [script] [options] [your_package_name]
# Options
# -w, --workspace=[your_package_name]
# Script
# dev/build/serve... 爱取啥取啥
# Exampe
# npm run start --workspace=react-start-with-webpack
其中 script
是 package
里面的子项目的 package.json
中配置的 script
属性
monorepo 的优势
减少重复依赖
缩短启动时间
由于避免了重复安装依赖,再去启动一个项目会快很多,当你有了单一代码库(monorepo
)的基础后,你再去开一个子项目,再去 npm install
,会发现非常快,总是 up to date
D:\fe-project\engineering-learning>npm install -w react-start-with-webpack
up to date in 1s
而且对于初始化 monorepo
是不需要下载全部依赖的,可以单一下载某个项目
npm install [options] [package]
# Options
# -w, --workspace=[your_package_name]
# Example
# npm install -w vue2-start-with-vite
不过对于有缓存机制的 node.js 来说,下载一次并不需要多久,更何况还有国内镜像
减少项目大小
通过减少重复依赖从而减少整个项目的大小,关于这个可能会认觉得我吹水,因为几乎很多介绍 monorepo
的文章曾经写过
谷歌拥有有史以来最大的代码库,每天有成百上千次提交,整个代码库超过 80 TB
我当下意识的以为使用 monorepo
技术是否会带来很大的硬盘压力,但实际上使用会发现,因为存在共同依赖的关系,多个项目的集成会避免下载重复的依赖,比如文章的这个例子
它是由四个子项目重新集成到一个 monorepo
库中,但是在大小上并不是 1 + 1 + 1 + 1 = 4
,实际的大小减少了 46.83%
(由于都是只有几次提交的项目,因此 .git
目录的大小可以忽略不计)
但是硬盘价格并不是很突出的今天,就算每个项目起步 1G
也并不是很贵
至于劣势,比如依赖冲突处理、团队推动成本、迁移成本、学习成本。。。(不过我认为最重要的还是背锅问题,毕竟老项目又不是不能用)
总结
这篇文章的 monorepo
只是一个跟风的玩具,从众多资料显示 monrepo
存在已久,并且众多团队曾经在单一代码库和多代码库中多次切换,很明显 monorepo
是一个很偏工程的技术,需要熟练的经验,需要充分理解它的理论。回到文章中实践的 monorepo
,只是一次技术上的实践,笔者对它的大多数理论场景没有涉及,不过用来了解一下新技术也是不错的
参考资料
转载自:https://juejin.cn/post/7181486158667317308