现代前端工程化——探秘 Monorepo 仓库管理方式

本文主要是介绍现代前端工程化——探秘 Monorepo 仓库管理方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

monorepo 和 multirepo

一般大到分项目,小到写代码,都遵循着拆分的原则,尽量不在一个项目、方法里糅合太多的东西。对于这种管理仓库的风格,称之为 multirepo。这样做的好处是,按不同项目可以分为多个仓库,仓库之间保证独立,独立开发独立部署,保证了每个项目之间不受其他项目影响。

另一种风格就是 monorepo了,也就是把多个项目放到一个仓库中,虽然把所有东西放到一起听起来很糟糕,但不仅仅是这样。对于 monorepo 而言,你只是把多个项目按你所设的某种场景把它组织到了一起,它的粒度还是保持原有的划分,对于某个团队的某个开发人员而言,他的关注点还是在其中一个项目。可能听上去这种方式相对于 multirepo 而言有些多此一举,我已经把仓库拆分了,为何还要再组织回去呢?对于一些前端项目而言,它的确有组织回去的好处,接下来就具体分析一下。

monorepo 并不是一种工具,它只是对于项目的一种管理手段,一种思维方式。

monorepo 的优点

简化组织

很大一部分情况下,我们在一开始开发项目的时候并不能保证项目的规模只有这么大,随着不断的迭代业务会越来越多,逻辑越来越复杂,于是就要对项目进行拆分。又或者是几个不同的但都处于某一块业务的项目。用这时候使用 monorepo 的方式来管理这些项目,能够简化项目结构组织。用 Dan Luu(参考文档三)的观点来说,很多拆分都不是正确的拆分。可能只是因为代码量多,或其他非必要原因对仓库进行了拆分。那就需要再重新将他们组织回来。

减少重复依赖项

对于前端项目,npm installnpm run dev 这些步骤已经刻在我们的基因里了。但是 install 安装了庞大的 node_modules 后,其实大部分项目所安装的库都有重复。那我们应该把这些依赖项提取出来,而都引用了这些依赖的子项目只需要通过软链接这样的方式引入依赖项即可。

跨项目开发

如果我们同时在给几个 npm 模块进行功能迭代开发,在多个仓库下调试起来可能不是那么方便,还需要手动维护 npm link,通过 monorepo 可以直接在本地进行夸项目间的联调,提高开发的效率。

更方便的仓库管理

对于一些大型、开源的项目来说,多个仓库意味着你要在多个地方进行 issue 之类的处理,你会更倾向于统一这些类似的 issue,管理很多 PR 和 git 钩子等等。

实践

Lerna

前面有讲过,既然 monorepo 不是工具,那我们就需要一个工具来实现它,在参考了一些文章后,我决定使用 Lerna(参考文档二)。

A tool for managing JavaScript projects with multiple packages.

这是 Lerna 官网对于它作用的描述,用来管理多个 JS 项目。不仅可以用 Lerna 来实现对多个项目仓库的管理,也可以用来管理多个 npm 包的维护发布。vue-cli(参考文档五),Babel(参考文档六)等知名项目也使用了 Lerna,大佬们都用了,那我们跟着梭哈就完事儿了。

然后我们只要通过命令 npm install --global lerna 将 Lerna 安装到全局。然后就可以开始了。

通过命令 lerna init 来初始化 Lerna 的目录,初始化完可以看到目录特别简单:

- packages
- package.json
- lerna.json

我们只要把项目放到 packages 文件夹下面即可。

在 lerna.json 中就是对 Lerna 的一些配置了,package.json 是用来管理主仓库的依赖之类的。

lerna.json

{"npmClient": "npm","packages": ["packages/*"],"version": "0.0.0"
}

npmClient 指定了安装使用的方式,可以用 npm 也可以用 yarn。packages 里面定义了子项目的路径,可以根据你想要的逻辑自由定义路径。

那么接下来就要实现一下刚才提到的关于依赖项的优化,Lerna 提供了一个命令:lerna bootstrap 来安装所有 package 的依赖项。运行这个命令相当于给每个项目都运行了 npm install。可我们想要的是把所有 package 的共同依赖提取到一个公共的地方,所以 Lerna 也提供了参数 --hoist 来提取共同的依赖项到主项目的 node_modules 中。

运行命令:lerna bootstrap --hoist

这时候主项目中会有一个 node_modules 里面放了一些公共的依赖,而用到了该依赖的项目,会在 node_modules/.bin 这个目录下生成一些符号链接来连接到公共的 node_modules(软链接)。这样就无需修改每一个项目的 package.json 了。

说到这里,有一个问题。如果项目中依赖的包版本不同怎么办?比如 A 项目使用了 Vue3,B 还在使用 Vue2.6。

Lerna 对于版本问题的解决方式是在公共的 node_modules 中安装版本最高的,再在低版本项目的node_modules 中独立为期安装依赖,并且在命令行中抛出警告。比如我在两个子项目中一个安装了 Vue2.6,另一个安装了 Vue3.0。

同时这样我们也可以清楚的发现不同项目中依赖的包版本有差异的问题,有时候我们最先做的 A 项目安装某一个包时,安装了 2.6.1 版本,之后在 B 项目中安装该依赖时已经有了 2.8.1 版本。这两个版本或许可以直接升级,并不会造成影响。但是手动去维护不同项目的依赖版本效率又特别低,通过 Lerna 可以很清楚的发现这样的版本差异问题。

如果需要开发多个 npm 包也能够使用 Lerna,就像 vue-cli 那样。简单举个例子,我们先创建两个项目:

lerna create module-a
lerna create module-b

根据命令行提示配置好一些 npm 的基本信息后,就能在目录下看到项目了:

- packages- module-a- __tests__ - lib- module-a.js- package.json- README.md- module-b- __tests__ - lib- module-b.js- package.json- README.md

在 module-a.js 中引入模块 b,并把模块 b 添加到模块 a 的依赖项中:

module-a.js

const moduleB = request('module-b');

package.json

"dependencies": {"module-b": "0.0.1"
},

然后运行命令 lerna link 后就能看到模块a中的 node_modules 引入了模块b的软链接。

开发完成后,就要把 npm 包发布到对应的仓库了,可以通过命令 lerna publish 发布。

到这里维护各个 npm 模块的流程就结束了,但是按照 multirepo 的话,我们可能要做几件事:

  1. 修改 module-b 的版本号

  2. 因为 module-a 依赖了 module-b,先修改 module-a 的依赖,再修改版本号

  3. 逐个发布包

这次只是个例子,如果实际开发中有几十个 npm 互相依赖就会造成不小的困扰了。那么对于其他的命令和详细的用法可以参考 Lerna 的文档(参考文档七)。

submodule

还有一种思路,在 Lerna 项目中,我们可以通过 git submodule 来引入不同的子项目仓库(Lerna 项目本身也是一个仓库,称之为主仓库)。

可以在 Lerna 项目根目录运行命令 git submodule add git@github.com:CUndH/mono-subA.git packages/ ,把一个 git 仓库放到 packages 下面。添加后,就可以在根目录下看到一个名为 .gitmodules 的文件,大致如下:

[submodule "packages/mono-subB"]path = packages/mono-subBurl = git@github.com:CUndH/mono-subB.git
[submodule "packages/mono-subA"]path = packages/mono-subAurl = git@github.com:CUndH/mono-subA.git

很清晰,不用多解释,就是一些子仓库的配置信息。

这时候,如果我是负责 mono-subA 项目的开发人员,我不需要去了解主仓库相关的信息。我的关注点还是在 mono-subA 项目上,而主项目不参与具体业务开发,只用于管理项目的版本、发布,便于导航、查阅代码提交日志等,可以交由负责人或者 CI 去进行一些拉取合并代码、发布生产环境等操作。

可以通过 git diff 命令清楚的看到不同子仓库的修改记录:

-dirty 后缀代表这一次修改还没被 commit。

在主项目中添加子项目的时候,git submodule 所添加的子仓库会对应到具体的某一次 commit 上,具体对应的 commit 是当前主项目中对于子项目最近的一次修改。所以在仓库里会这样显示:

所以如果子仓库开发完毕提交了代码后,主仓库所指向的子仓库还是前一次 commit 的仓库,我查了一些文档说可以通过 git submodule update --remote 来获取子仓库的最新代码,这里有个小问题。如果直接运行该命令可能会报错,因为 git 会默认拉取子仓库的 origin/master 分支代码,而现在在 github 创建新仓库默认只有 main 分支了。如果你想要指定子仓库的拉取分支,你可以在 .gitmodules 文件中配置 branch:

[submodule "packages/mono-subA"]path = packages/mono-subAurl = git@github.com:CUndH/mono-subA.gitbranch = main  // 加上这行

对于子仓库的修改,当你 commit 和 push 之后,在主仓库也会有一个待提交的 commit,需要再在主仓库中再提交一遍更新才行,这里有点多此一举的味道,但是我认为这可以更好的控制多个子项目的版本的一致性。假设我们每周会更新一次主仓库来进行发布生产环境这样的操作,那么这一步就能确保主仓库可以准确的控制某一个子仓库的代码更新,而不会因为不可控引起一颗老鼠屎坏一锅粥的情形。

monorepo 的缺点

无论是对于代码层面的设计,亦或是仓库管理层面的设计思想,都像踩跷跷板一样,没有最好,只有最适合。所以 monorepo 也有一些不足的地方:

  • 无法管理某个、某些项目对于指定人员的权限

  • 不同分支下的版本控制会显得较为混乱

  • 对于发布构建的挑战,难度会比单个项目构建要大

  • 不适用于业务相对零散、项目之间关系不大的场景

结尾

monorepo 和 multirepo 并没有哪个更胜一筹,只是不同的管理方式而已,本文也并不是说 monorepo 更好,我查阅的一些文章中也看到了不少反对意见,只要能从中学习到自己本不了解的东西就好,况且在现实中我们对于类似的技术的学习和使用本就不应该做选择题。

参考

  • 文档一:Git 命令 - submodule:https://git-scm.com/docs/git-submodule

  • 文档二:Lerna 官网:https://lerna.js.org/

  • 文档三:dan luu 的博客:https://danluu.com/monorepo/

  • 文档四:Monorepo 可能没你想象的那么香:https://baijiahao.baidu.com/s?id=1663844045880515134&wfr=spider&for=pc

  • 文档五:vue-cli:https://github.com/vuejs/vue-cli

  • 文档六:Babel:https://github.com/babel/babel

  • 文档七:lerna 文档:https://github.com/lerna/lerna

全文完


以下文章您可能也会感兴趣:

  • Linux 的 IO 通信 以及 Reactor 线程模型浅析

  • 浅谈 BI 与数据分析的可视化

  • iOS 照片涂鸦功能的实现

  • 捋一捋 App 性能测试中的几个重要概念

  • 所谓 Serverless,你理解对了吗?

  • 如何写好产品中的提示文案

  • Web 开发打印总结

  • JVM 揭秘: 一个 class 文件的前世今生

  • Android 图片编辑的原理与实现 -- 涂鸦与马赛克

  • 微服务环境下的集成测试探索(二)—— 契约式测试

  • 微服务环境下的集成测试探索(一) —— 服务 Stub & Mock

  • Objective-C 中的语法糖

  • Facebook、Google、Amazon 是如何高效开会的

  • 谈谈到底什么是抽象,以及软件设计的抽象原则

  • 后端的缓存系统浅谈

  • 从 React 到 Preact 迁移指南

  • 如何成为一名数据分析师:数据的初步认知

  • 复杂业务状态的处理:从状态模式到 FSM

  • 聊聊移动端跨平台数据库 Realm

我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。

这篇关于现代前端工程化——探秘 Monorepo 仓库管理方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/181636

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能