资讯专栏INFORMATION COLUMN

Monorepo——大型前端项目的代码管理方式

ziwenxie / 3545人阅读

摘要:目前最常见的解决方案是和的特性。具体的使用方法移步官网而使用作为包管理器的同学,可以在中以字段声明,就会以的方式管理。这样的话,无论你的包管理器是还是,都能发挥的优势要是包管理是,就会把依赖安装交给处理。

最近我接手了一个项目,代码量比较大、有点复杂。仓库 clone 下来代码有 50+ MB,npm install 安装完体积飚到了近 2GB …… 熟悉了一下,这个项目比较复杂,采用了 monorepo 的方式进行代码的管理。折腾几天后,对 monorepo 也有个大概的了解……

Monorepo

Monorepo 是管理项目代码的一个方式,指在一个项目仓库 (repo) 中管理多个模块/包 (package),不同于常见的每个模块建一个 repo。

目前有不少大型开源项目采用了这种方式,如 Babel:

How is the repo structured?
The Babel repo is managed as a monorepo that is composed of many npm packages.

还有 create-react-app, react-router 等。可以看到这些项目的第一级目录的内容以脚手架为主,主要内容都在 packages 目录中、分多个 package 进行管理。

├── packages
|   ├── pkg1
|   |   ├── package.json
|   ├── pkg2
|   |   ├── package.json
├── package.json

monorepo 最主要的好处是统一的工作流Code Sharing。比如我想看一个 pacakge 的代码、了解某段逻辑,不需要找它的 repo,直接就在当前 repo;当某个需求要修改多个 pacakge 时,不需要分别到各自的 repo 进行修改、测试、发版或者 npm link,直接在当前 repo 修改,统一测试、统一发版。只要搭建一套脚手架,就能管理(构建、测试、发布)多个 package

不好的方面则主要是 repo 的体积较大。特别是,因为各个 package 理论上都是独立的,所以每个 package 都维护着自己的 dependencies,而很大的可能性,package 之间有不少相同的依赖,而这就可能使install时出现重复安装,使本来就很大的 node_modues 继续膨胀(我称这为「依赖爆炸」...)。

基于对以上的理解,我认为当项目到一定的复杂度,需要且可以划分模块、但模块间联系紧密的,比较适合用 monorepo 组织代码。

目前最常见的 monorepo 解决方案是 Lerna 和 yarnworkspaces 特性。其中,lerna 是一个独立的包,其官网的介绍是:

a tool that optimizes the workflow around managing multi-package repositories with git and npm.

上面提到的 Babel, create-react-app 等都是用 lerna 进行管理的。在项目 repo 中以lerna.json声明 packages 后,lerna 为项目提供了统一的 repo 依赖安装 (lerna bootstrap),统一的执行 package scripts (lerna run),统一的 npm 发版 (lerna publish) 等特性。对于「依赖爆炸」的问题,lerna 在安装依赖时提供了--hoist选项,相同的依赖,会「提升」到 repo 根目录下安装,但……太鸡肋了,lerna 直接以字符串对比 dependency 的版本号,完全相同才提升,semver 约定在这并不起作用。

具体的使用方法移步 Lerna 官网:https://lerna.js.org

而使用 yarn 作为包管理器的同学,可以在 package.json 中以 workspaces 字段声明 packages,yarn 就会以 monorepo 的方式管理 packages。相比 lerna,yarn 突出的是对依赖的管理,包括 packages 的相互依赖、packages 对第三方的依赖,yarn 会以 semver 约定来分析 dependencies 的版本,安装依赖时更快、占用体积更小;但欠缺了「统一工作流」方面的实现。

yarn 官网对 workspace的详细说明:Workspaces | Yarn

lerna 和 yarn-workspace 并不是只能选其一,大多 monorepo 即会使用 lerna 又会在 package.json 声明 workspaces。这样的话,无论你的包管理器是 npm 还是 yarn,都能发挥 monorepo 的优势;要是包管理是 yarn ,lerna 就会把依赖安装交给 yarn 处理。

再说回我那项目呢,安装依赖后体积实在是大,折腾了两天想要优化一下,但目前大量脚本严重依赖 npm,我……

还是后面考虑慢慢迁移到 yarn 吧。

Reference

babel/monorepo.md at master · babel/babel

EHOIST_ROOT_VERSION warning hoisting question · Issue #872 · lerna/lerna

Others git-submodule

通过 Git 子模块,可以在当前 repo 中包含其它 repos、作为当前 repo 的子目录使用,同时能够保持 repos 之间的独立。

# 在当前 repo 添加一个子模块
git submodule add git@github.com:xxx/xxx.git path/to/xxx

可以在 .gitmodule文件中看到当前 repo 有哪些 submodule,分别的 name, branch 等。

# clone 含有 submodule 的 repo 后:
# 初始化 git submodule 信息
git submodule init
# 更新 submodule,相当于 git pull 吧
git submodule update

修改子模块文件后,在当前 repo 执行 git status 只会看到有模块的 changes,而不是具体子模块文件:

diff --git a/path/to/submodule b/path/to/submodule
--- a/path/to/submodule
+++ b/path/to/submodule
@@ -1 +1 @@
-Subproject commit xxxxxxx
+Subproject commit xxxxxxx-dirty

dirty表示子模块的修改还不是 commit。如果子模块的修改 commit 后,这个改动就会是具体的 commit id。

子模块的其它 commit, pull 等各操作,还是到其目录下,按普通 repo 操作即可。

Reference

Git - 子模块:

https://git-scm.com/book/zh/v...

man git-submodule

git submodules - Git diff says subproject is dirty - Stack Overflow

https://stackoverflow.com/que...

git-bisect

git 有一个以二分法帮助定位问题的命令——bisect

# 开始二分查找问题
git bisect start
# 标记当前有问题
git bisect bad
# 标记哪个 commit 或 tag 时是没问题的
git bisect good v1.0.0

# 此时 git 会 checkout 两个点之间的某个 commit,
# 如果此时还是有问题:
git bisect bad
# 如果此时没有问题:
git bisect good
# 接着 git 会 checkout 下一个「有问题」和「没问题」之间的 commit

# 直到定位到问题,git 会提示:xxxxxxx is first bad commit
Reference

使用 Git 调试

https://git-scm.com/book/zh/v...

欢迎关注我的订阅号——「车迷与码农」,不定期分享关于前端、汽车和有趣的事儿~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109885.html

相关文章

  • 精读《Monorepo 优势》

    摘要:引言本周精读的文章是。精读总的来说,虽然拆分子仓库拆分子包是进行项目隔离的天然方案,但当仓库内容出现关联时,没有任何一种调试方式比源码放在一起更高效。前端精读帮你筛选靠谱的内容。 1. 引言 本周精读的文章是 The many Benefits of Using a Monorepo。 现在介绍 Monorepo 的文章很多,可以分为如下几类:直接介绍 Lerna API 的;介绍如何...

    xcc3641 评论0 收藏0
  • lerna管理package

    摘要:最近发现公司一个项目的目录组织挺奇怪的,所有的子项目都放在了目录里,还有这种骚操作特意查了下资料,发现是一种比较流行的项目管理模式。 最近发现公司一个项目的目录组织挺奇怪的,所有的子项目都放在了packages目录里,还有这种骚操作?特意查了下资料,发现是一种比较流行的monorepo项目管理模式。近几年比较火的React,Vue,Babel都是用的这种模式: showImg(http...

    PumpkinDylan 评论0 收藏0
  • 说明Yarn与Lerna管理monorepo使用

       我们先说下 Yarn workspace  首先Yarn workspace 是 Yarn 提供的 monorepo 下,管理依赖的机制。这就说主要对代码仓库下,多个 package 的依赖,进行管理:将共同的依赖,做 hosting(提升)。前述这样就可以有效的防止 package 中的包重复安装。 workspace 机制,会在根目录下,统一安装依赖到 node_module,并生成...

    3403771864 评论0 收藏0
  • 两年React老兵总结 - 如何组织React项目

    摘要:一个复杂的应用都是由简单的应用发展而来的随着越来越多的功能加入项目代码就会变得越来越难以控制本文章主要探讨在大型项目中如何对组件进行组织让项目具备可维护性系列目录类型检查组件的组织样式的管理组件的思维状态管理目录组件设计的基本原则基本原则高 一个复杂的应用都是由简单的应用发展而来的, 随着越来越多的功能加入项目, 代码就会变得越来越难以控制. 本文章主要探讨在大型项目中如何对组件进行组...

    hoohack 评论0 收藏0
  • 简单说说 angular.json 文件

    摘要:指向一个文件,这个文件描述了所有的字段以及约束。其中一个项目为一个子项,如为一个项目,在创建时自动生成。整个也有此字段,默认生效于所有。默认项目,当使用一些命令没有指定项目名称时,默认指向的项目。 ... 在Angular CLI 6+的版本后,原先的angular-cli.json就被换成了angular.json,而其中里面的字段变化挺大了,如果不了解基本的组成,或者直接把老版本的...

    wangjuntytl 评论0 收藏0

发表评论

0条评论

ziwenxie

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<