共计 11702 个字符,预计需要花费 30 分钟才能阅读完成。
0. ???? 前言
在最近的我的项目开发中,呈现了一个令我困扰的情况。我正在开发的我的项目 A,依赖了曾经线上公布的我的项目 B,然而随着我的项目 A 的一直开发,又须要不断批改我的项目 B 的代码(这些批改临时不用公布线上),如何可能在批改我的项目 B 代码后及时将改变后在我的项目 A 中同步? 在我的项目 A 公布上线后,如何以一种优雅的形式解决我的项目 A,B 版本升级后的版本同步问题? 通过一番调研,我发现解决这些问题的最佳计划便是本篇要介绍的 monorepo 策略。
1. ???? 什么是 monorepo 策略?
monorepo 是一种 将多个我的项目代码存储在一个仓库里的软件开发策略 (”mono” 来源于希腊语 μόνος 象征 单个的,而 “repo”,不言而喻地,是 repository 的缩写)。将不同的我的项目的代码放在同一个代码仓库中,这种「把鸡蛋放在同一个篮子里」的做法可能乍看之下有些奇怪,但实际上,这种代码治理形式有很多益处,无论是世界一流的互联网企业 Google,Facebook,还是社区出名的开源我的项目团队 Babel(如下图)都应用了 monorepo 策略管理他们的代码。
<p style=”text-align: center; color: #999;”>babel 应用 monorepo 策略管理代码 </p>
应用 monorepo 策略到底会给代码管理者和程序开发者带来哪些益处? 咱们又该如何在工作中尝试实际 monorepo 策略?这正是本文想要探讨的话题。心愿通过我的一番介绍,您可能对 monorepo 策略有更残缺的认知,文章中介绍的工具和思维能够切实帮忙到您和您所在的团队。
2. ???? monorepo 策略的优劣
通过 monorepo 策略组织代码,您代码仓库的目录构造看起来会是这样:
.
├── lerna.json
├── package.json
└── packages/ # 这里将寄存所有子 repo 目录
├── project_1/
│ ├── index.js
│ ├── node_modules/
│ └── package.json
├── project_2/
│ ├── index.js
│ ├── node_module/
│ └── package.json
...
乍看起来,所谓的 monorepo 策略就只是将不同我的项目的目录会集到一个目录之下,但实际上操作起来所要思考的事件则远比看起来要简单得多。通过剖析应用 monorepo 策略的优劣,咱们能够更直观的感触到这外面所费解波及的知识点。
2.1 monorepo 计划的劣势
- 代码重用将变得非常容易:因为所有的我的项目代码都集中于一个代码仓库,咱们将很容易抽离出各个我的项目共用的业务组件或工具,并通过 TypeScript,Lerna 或其余工具进行代码内援用;
- 依赖治理将变得非常简单:同理,因为我的项目之间的援用门路内化在同一个仓库之中,咱们很容易追踪当某个我的项目的代码批改后,会影响到其余哪些项目。通过应用一些工具,咱们将很容易地做到版本依赖治理和版本号主动降级;
- 代码重构将变得十分便捷:想想到底是什么在阻止您进行代码重构,很多时候,起因来自于「不确定性」,您不确定对某个我的项目的批改是否对于其余我的项目而言是「致命的」,出于对未知的恐怖,您会偏向于不重构代码,这将导致整个我的项目代码的腐烂度会以惊人的速度增长。而在 monorepo 策略的领导下,您可能明确晓得您的代码的影响范畴,并且可能对被影响的我的项目能够进行对立的测试,这会激励您一直优化代码;
- 它提倡了一种凋谢,通明,共享的组织文化,这有利于开发者成长,代码品质的晋升:在 monorepo 策略下,每个开发者都被激励去查看,批改别人的代码(只有有必要),同时,也会激发开发者保护代码,和编写单元测试的责任心(毕竟敌人来访之前,咱们从不介意本人的房子到底有多乱),这将会造成一种良性的技术气氛,从而保障整个组织的代码品质。
2.2 monorepo 计划的劣势
- 我的项目粒度的权限治理变得非常复杂:无论是 Git 还是其余 VCS 零碎,在反对 monorepo 策略中我的项目粒度的权限治理上都没有令人满意的计划,这意味着 A 部门的 a 我的项目若是不想被 B 部门的开发者看到就很难了。(好在咱们能够将 monorepo 策略实际在「我的项目级」这个档次上,这才是咱们这篇文章的主题,咱们前面会再次明确它);
- 新员工的学习老本变高:不同于一个我的项目一个代码仓库这种模式下,组织新人只有相熟特定代码仓库下的代码逻辑,在 monorepo 策略下,新人可能不得不花更多精力来理清各个代码仓库之间的互相逻辑,当然这个老本能够通过新人文档的形式来解决,但保护文档的陈腐又须要耗费额定的人力;
- 对于公司级别的 monorepo 策略而言,须要专门的 VFS 零碎,主动重构工具的反对:构想一下 Google 这样的企业是如何将十亿行的代码存储在一个仓库之中的?开发人员每次拉取代码须要期待多久?各个我的项目代码之间又如何实现权限治理,麻利公布?任何简略的策略乘以足够的规模量级都会产生一个奇观(不论是好是坏),对于中小企业而言,如果没有像 Google,Facebook 这样雄厚的人力资源,把所有我的项目代码放在同一个仓库里这个美妙的欲望就只能是个海市蜃楼。
2.3 小结:如何取舍?
没错,软件开发畛域素来没有「银弹」。monorepo 策略也并不完满,并且,我在实践中发现,要想完满在组织中使用 monorepo 策略,所须要的不仅是杰出的编程技巧和急躁。团队日程 , 组织文化 和集体影响力 互相碰撞的最终后果才决定了想法最终是否能被实现。
然而请别灰心的太早,因为尽管让组织作出扭转,对立实施 monorepo 策略困难重重,但这却并不意味着咱们须要彻底跟 monorepo 策略说再见(否则我这篇文章就该到此为止了)。咱们还能够 把 monorepo 策略实际在「我的项目」这个级别,即从逻辑上确定我的项目与我的项目之间的关联性,而后把相关联的我的项目整合在同一个仓库下,通常状况下,咱们不会有太多互相关联的我的项目,这意味着咱们可能收费失去 monorepo 策略的所有益处,并且能够回绝领取大型 monorepo 架构的利息。
本文的残余篇幅就是对「我的项目级别 monorepo 实际」的一些总结,即便您最终没有抉择 monorepo 策略组织您的代码,置信文章中提供的一些工程化工具或思路也一样会对您产生帮忙。
3. ???????????? monorepo 计划实际
3.1 锁定环境:Volta
Volta 是一个 JavaScript 工具管理器,它能够让咱们轻松地在我的项目中锁定 node,npm 和 yarn 的版本。你只需在装置完 Volta 后,在我的项目的根目录中执行 volta pin
命令,那么无论您以后应用的 node 或 npm(yarn)版本是什么,volta 都会主动切换为您指定的版本。
因而,除了应用 Docker 和显示在文档中申明 node 和 npm(yarn)的版本之外,您就有了另一个锁定环境的强力工具。
而且相较于 nvm,Volta 还具备一个迷人的个性:当您我的项目的 CLI 工具与全局 CLI 工具不统一时,Volta 能够做到在我的项目根目录下自动识别,切换到我的项目指定的版本,这一切都是由 Volta 默默做到的,开发者不用关怀任何事件。
3.2 复用 packages:workspace
应用 monorepo 策略后,收益最大的两点是:
- 防止反复安装包,因而缩小了磁盘空间的占用,并升高了构建工夫;
- 外部代码能够彼此互相援用;
这两项益处全副都能够由一个成熟的包管理工具来实现,对前端开发而言,即是 yarn
(1.0 以上)或 npm
(7.0 以上)通过名为 workspaces
的个性实现的(⚠️ 留神,反对 workspaces 个性的 npm 目前仍旧不是 TLS 版本)。
为了实现后面提到的两点收益,您须要在代码中做三件事:
- 调整目录构造,将互相关联的我的项目搁置在同一个目录,举荐命名为
packages
; - 在我的项目根目录里的
package.json
文件中,设置workspaces
属性,属性值为之前创立的目录; - 同样,在
package.json
文件中,设置private
属性为true
(为了防止咱们误操作将仓库公布);
通过批改,您的我的项目目录看起来应该是这样:
.
├── package.json
└── packages/
├── @mono/project_1/ # 举荐应用 `@< 我的项目名 >/< 子项目名 >` 的形式命名
│ ├── index.js
│ └── package.json
└── @mono/project_2/
├── index.js
└── package.json
而当您在我的项目根目录中执行 npm install
或 yarn install
后,您会发现在我的项目根目录中呈现了 node_modules
目录,并且该目录不仅领有所有子项目共用的 npm 包,还蕴含了咱们的子项目。因而,咱们能够在子项目中通过各种模块引入机制,像引入个别的 npm 模块一样引入其余子项目的代码。
请留神咱们对子我的项目的命名,对立以 @<repo_name>/
结尾,这是一种社区最佳实际,不仅能够让用户更容易理解整个利用的架构,也不便您在我的项目中更快捷的找到所需的子项目。
至此,咱们曾经实现了 monorepo 策略的外围局部,切实是很容易不是吗?然而老话说「行百里者半九十」,间隔优雅的搭建一个 monorepo 我的项目,咱们还有一些路要走。
3.3 对立配置:合并同类项 – Eslint,Typescript 与 Babel
您肯定批准,编写代码要遵循 DRY 准则(Don’t Repeat Yourself 的缩写)。那么,天经地义地,咱们应该尽量避免在多个子项目中搁置反复的 eslintrc,tsconfig 等配置文件。侥幸的是,Babel,Eslint 和 Typescript 都提供了相应的性能让咱们缩小自我反复。
3.3.1 TypeScript
咱们能够在 packages
目录中搁置 tsconfig.settting.json
文件,并在文件中定义通用的 ts 配置,而后,在每个子项目中,咱们能够通过 extends
属性,引入通用配置,并设置 compilerOptions.composite
的值为 true
,现实状况下,子项目中的 tsconfig
文件应该仅蕴含下述内容:
{
"extends": "../tsconfig.setting.json", // 继承 packages 目录下通用配置
"compilerOptions": {
"composite": true, // 用于帮忙 TypeScript 疾速确定援用工程的输入文件地位
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
3.3.2 Eslint
对于 Eslint 配置文件,咱们也能够如法炮制,这样定义子项目的 .eslintrc
文件内容:
{
"extends": "../../.eslintrc", // 留神这里的不同
"parserOptions": {"project": "tsconfig.json"}
}
留神到了吗,对于通用的 eslint 配置,咱们并没有将其搁置在 packages
目录中,而是放在整个我的项目的根目录下,这样做是因为一些编辑器插件只会在我的项目根目录寻找 .eslintrc
文件,因而为了咱们的我的项目可能保持良好的「开发环境一致性」,请务必将通用配置文件搁置在我的项目的根目录中。
3.3.3 Babel
Babel 配置文件合并的形式与 TypeScript 一模一样,甚至更加简略,咱们只需在子项目中的 .babelrc
文件中这样申明即可:
{"extends": "../.babelrc"}
当所有准备就绪后,咱们的我的项目目录应该大抵呈如下所示的构造:
.
├── package.json
├── .eslintrc
└── packages/
│ ├── tsconfig.settings.json
│ ├── .babelrc
├── @mono/project_1/
│ ├── index.js
│ ├── .eslintrc
│ ├── .babelrc
│ ├── tsconfig.json
│ └── package.json
└───@mono/project_2/
├── index.js
├── .eslintrc
├── .babelrc
├── tsconfig.json
└── package.json
3.4 对立命令脚本:scripty
在上一步中,咱们尽可能的将所有配置文件进行形象,从而精简了代码,并进步了整个我的项目的一致性。咱们的整个仓库也因而有了「更浓烈的 monorepo 风味 ☕️」。但如果认真扫视咱们的整个工程文件,还有一处存在着显著的瑕疵和一些宜人的坏滋味,当您认真扫视您的泛滥 package.json
文件时,您就晓得我在说什么了 — scripts 脚本。
如果您的子项目足够多,您可能会发现,每个 package.json
文件中的 scripts
属性都大同小异,并且一些 scripts
充斥着各种 Linux 语法,例如管道操作符,重定向或目录生成。反复带来低效,简单则使人难以了解,这都是须要咱们解决的问题。
这里给出的解决方案是,应用 scripty 治理您的脚本命令,简略来说,scripty 容许您将脚本命令定义在文件中,并在 package.json
文件中间接通过文件名来援用。这使咱们能够实现如下目标:
- 子项目间复用脚本命令;
- 像写代码一样编写脚本命令,无论它有多简单,而在调用时,像调用函数一样调用;
通过应用 scripty 治理咱们的 monorepo 利用,目录构造看起来将会是这样:
.
├── package.json
├── .eslintrc
├── scirpts/ # 这里寄存所有的脚本
│ │ ├── packages/ # 包级别脚本
│ │ │ ├── build.sh
│ │ │ └── test.sh
│ └───└── workspaces/ # 全局脚本
│ ├── build.sh
│ └── test.sh
└── packages/
│ ├── tsconfig.settings.json
│ ├── .babelrc
├── @mono/project_1/
│ ├── index.js
│ ├── .eslintrc
│ ├── .babelrc
│ ├── tsconfig.json
│ └── package.json
└── @mono/project_2/
├── index.js
├── .eslintrc
├── .babelrc
├── tsconfig.json
└── package.json
留神,咱们脚本分为两类「package 级别」与「workspace 级别」,并且别离放在两个文件夹内。这样做的益处在于,咱们既能够在我的项目根目录执行全局脚本,也能够针对单个我的项目执行特定的脚本。
通过应用 scripty,子项目的 package.json
文件中的 scripts
属性将变得十分精简:
{
...
"scripts": {
"test": "scripty",
"lint": "scripty",
"build": "scripty"
},
"scripty": {"path": "../../scripts/packages" // 留神这里咱们指定了 scripty 的门路},
...
}
功败垂成!???? 至此,咱们尽己所能地删除了整个我的项目中的反复代码,让整个我的项目变得洁净,清新并且有极强的复用性。
???? 小贴士:
别忘了应用 chmod -R u+x scripts 命令使所有的 shell 脚本具备可执行权限,也千万别忘了把这条贴士写在您的 README.md 文件中!
3.5 对立包治理:Lerna
<p style=”text-align: center; color: #999;”> 图片起源:https://github.com/lerna/lerna</p>
我有时会感叹本人的灵感匮乏,怎么就想不到 Lerna 这样既有神话色调又能自我释义的好名字。您能够大胆设想,九头龙的每只龙头都在帮您治理着一个子项目,而您只须要骑在龙身上发号施令的场景,这基本上就是咱们应用 Lerna 时的直观感触。
这也是为什么当咱们提起 monorepo 策略,就简直不得不提到 Lerna 的起因了,它确实提供了一种十分便捷的形式供咱们治理 monorepo 我的项目。当子项目越多时,Lerna 就越能显示其威力。
当多个子项目放在一个代码仓库,并且子项目之间又相互依赖时,咱们面临的辣手问题有两个:
- 如果咱们须要在多个子目录执行雷同的命令,咱们须要手动进入各个目录,并执行命令;
- 当一个子项目更新后,咱们只能手动追踪依赖该项目标其余子项目,并降级其版本。
通过应用 Lerna,这些辣手的问题都将不复存在。
当在我的项目根目录应用 npx lerna init
初始化后,咱们的根目录会新增一个 lerna.json
文件,默认内容为:
{"packages": ["packages/*"],
"version": "0.0.0"
}
让咱们稍稍改变这个文件,使其变为:
{"packages": ["packages/*"],
"npmClient": "yarn",
"version": "independent",
"useWorkspaces": true,
}
能够留神到,咱们显示申明了咱们的包客户端(npmClient
)为 yarn
,并且让 Lerna 追踪咱们 workspaces 设置的目录,这样咱们就仍旧保留了之前 workspaces
的所有个性(子项目援用 和通用包晋升)。
除此之外一个乏味的改变在于咱们将 version
属性指定为一个关键字 independent
,这将通知 lerna 应该 将每个子项目的版本号看作是互相独立的。当某个子项目代码更新后,运行 lerna publish
时,Lerna 将监听到代码变动的子项目并以交互式 CLI 形式让开发者决定须要降级的版本号,关联的子项目版本号不会主动降级,反之,当咱们填入固定的版本号时,则任一子项目的代码变动,都会导致所有子项目的版本号基于以后指定的版本号降级。
Lerna 提供了很多 CLI 命令以满足咱们的各种需要,但依据 2/8 法令,您应该首先关注以下这些命令:
lerna bootstrap
:等同于lerna link
+yarn install
,用于创立合乎链接并装置依赖包;lerna run
:会像执行一个 for 循环一样,在所有子项目中执行 npm script 脚本,并且,它会十分智能的辨认依赖关系,并从根依赖开始执行命令;lerna exec
:像lerna run
一样,会依照依赖程序执行命令,不同的是,它能够执行任何命令,例如 shell 脚本;lerna publish
:公布代码有变动的 package,因而首先您须要在应用 Lerna 前应用git commit
命令提交代码,好让 Lerna 有一个 baseline;lerna add
:将本地或近程的包作为依赖增加至以后的 monorepo 仓库中,该命令让 Lerna 能够辨认并追踪包之间的依赖关系,因而十分重要;
# 向 @mono/project2 和 @mono/project3 中增加 @mono/project1
lerna add @mono/project1 '@mono/project{2,3}'
3.5.1 Lerna 高级命令
除了下面介绍到的常用命令外,Lerna 还提供了一些参数满足咱们更灵便的需要,例如:
--concurrency <number>
:参数能够使 Lerna 利用计算机上的多个外围,并发运行,从而晋升构建速度;--scope '@mono/{pkg1,pkg2}'
:--scope
参数能够指定 Lerna 命令的运行环境,通过应用该参数,Lerna 将不再是一把梭的在所有仓库中执行命令,而是能够精准地在咱们所指定的仓库中执行命令,并且还反对示例中的模版语法;--stream
:该参数可使咱们查看 Lerna 运行时的命令执行信息;
3.5.2 npm 包本地公布:Verdaccio
看到这里,您可能想要亲自体验一把应用 Lerna 治理 / 公布 monorepo 我的项目的感觉。可是很快您会发现,将示例代码公布到真实世界的 npm 仓库并非一个好主见,这多少有些令人丧气,然而别放心,您能够应用 Verdaccio 在本地创立一个 npm 仓库作为代理,而后纵情体验 Lerna 的种种弱小之处。
装置运行 Verdaccio 非常简单,您只需运行:
npm install --global verdaccio
在全局装置 Verdaccio 利用,而后在 shell 中输出:
verdaccio
即可通过 localhost:4837
拜访您的本地代理 npm 仓库,别忘了在您的我的项目根目录创立 .npmrc
文件,并在文件中将 npm 仓库地址改写为您的本地代理地址:
registry="http://localhost:4873/"
功败垂成 ????!每当您执行 lerna publish
时,子项目所构建成的 package 将会公布在本地 npm 仓库中,而当您执行 lerna bootstrap
时,Verdaccio 将会放行,让您胜利从近程 npm 仓库中拉取相应的代码。
3.6 格式化 commit 信息
至此,咱们曾经把握了组织一个我的项目级 monorepo 仓库的所有前沿技巧,最初,让咱们看看最初一个能够优化的中央:代码提交时,束缚 commit 信息。
一个 monorepo 仓库可能被 不同的开发者提交不同子项目 的代码,如果没有规范化的 commit 信息,在故障排查或版本回滚时毫无意外会遭逢劫难。因而,千万不要小看 commit 信息格式化的重要性(当然,同样重要的还有代码正文!)。
为了咱们可能高深莫测的追踪每次代码变更的信息,咱们应用 commitlint 工具作为格式化 commit 信息的不二之选。
顾名思义,commitlint
能够帮忙咱们查看提交的 commit 信息,它强制束缚咱们的 commit 信息必须在结尾附加指定类型,用于标示本次提交的大抵用意,反对的类型关键字有:
feat
:示意增加一个新个性;chore
:示意做了一些与个性和修复无关的「家务事」;fix
:示意修复了一个 Bug;refactor
:示意本次提交是因为重构了代码;style
:示意代码丑化或格式化;- …
我强烈建议您遵循该标准编写您的 commit 信息,不要偷懒,坚持下去,您的 git 日志将会显得参差,有条理,富裕表现力,同时,您也会收到同行的交口称赞,人人都会以和您这样优雅的工程师单干为荣。
除了限定 commit 信息类型外,commitlint 还反对(尽管不是必须的)显示指定咱们本次提交所对应的子项目名称。如果咱们有一个名为 @mono/project1
的子项目,咱们针对该我的项目提交的 commit 信息能够写为:
git commit -m "feat(project1): add a attractive button" # 留神,咱们省略了 @mono 的我的项目前缀
毫无疑问,这将会使咱们的 commit 信息更具表现力。
咱们能够通过上面的命令装置 commitlint
以及周边依赖:
npm i -D @commitlint/cli @commitlint/config-conventional @commitlint/config-lerna-scopes commitlint husky lerna-changelog
留神到了吗?我偷偷装置了 husky,它可能帮忙咱们在提交 commit 信息时主动运行 commitlint
进行查看,但在这之前,咱们须要再在根目录下的 package.json
文件里加点料,像这样:
{
...
"husky": {
"hooks": {"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"}
}
...
}
为了可能让 commitlint
感知咱们的子项目名称,咱们还需在我的项目根目录中减少 commitlint.config.js
文件,并设置文件内容为:
module.exports = {
extends: [
"@commitlint/config-conventional",
"@commitlint/config-lerna-scopes",
],
};
至此,咱们对立并规范化了 monorepo 我的项目的 commit 信息,终于整个 monorepo 工程化的最初一块拼图被咱们拼上了!
(顺便一提,您能够通过在命令行执行 echo "build(project1): change something" | npx commitlint
命令即可验证您的 commit 信息是否通过 commitlint 的查看。)
4. ???? 如何从 multirepo 迁徙至应用 monorepo 策略?
至此,咱们学会了如何采纳 monorepo 策略组织我的项目代码的最佳实际,或者您曾经开始蠢蠢欲动想要尝试前文提到的种种技巧。从 0 搭建一个 monorepo 我的项目,当然没问题!可是如果要基于已有的我的项目,将其转化为一个应用 monorepo 策略的我的项目呢?
还记得吗?成百里者半九十,您还有一些坑要踩。不过好在您在这里还可能失去我的帮忙,不用客气!
或者您留神到了,Lerna 为咱们提供了 lerna import
命令,用来将咱们已有的包导入到 monorepo 仓库,并且还会保留该仓库的所有 commit 信息。然而实际上,该命令仅反对 导入本地我的项目 ,并且 不反对 导入我的项目的分支和标签 ????。
那么如果咱们想要导入近程仓库,或是要获取某个分支或标签该怎么做呢?答案是应用 tomono,其内容是一个 shell 脚本。
应用 tomono 导入近程仓库,您所须要做的只有两件事:
- 创立一个蕴含所有须要导入 repo 地址的文本文件;
- 执行 shell 命令:
cat repos.txt | ~/tomono/tomono.sh
(这里咱们假设您的文本文件名为repos.txt
,且您将 tomono 下载在用户根目录;
repo 文件内容示例如下:
// 1. Git 仓库地址 2. 子项目名称 3. 迁徙后的门路
git@github.com/backend.git @mono/backend packages/backend
git@github.com/frontend.git @mono/frontend packages/frontend
git@github.com/mobile.git @mono/mobile packages/mobile
至此,咱们也把握了将现有我的项目迁徙至 monorepo 我的项目的办法。到这时候,您已绝非再是 monorepo 界的门外汉!
祝贺您!!????
5. ???? 小结
在本篇文章中,咱们独特理解了「什么是 monorepo 策略」以及「monorepo 策略的优劣」,并且一起学习实际了 monorepo 策略的一些最佳实际。您肯定也意识到,即便您的工作场景临时无奈实际 monorepo 策略,浏览本篇文章所学习到的种种办法,工具和思维也能够使用到您当下的工作之中。
当然,本文所介绍的这些办法和思维总有过期的一天,并且社区也从未进行对更好地实际 monorepo 策略的摸索,说不定您过一阵子就会有更好的想法,填补某个畛域的空白。心愿到时候您也能总结出一篇文章,为 JavaScript 社区奉献一份力量。到时候请千万别忘了回到我的评论区留言,让我分享您的成就。
对于 monorepo 这个主题,我就暂且带您摸索到这里,后会有期:)
6. ???? 参考文献
- ???? JavaScript and TypeScript Monorepos
- ???? Why you should use a single repository for all your company’s projects
- ???? Advantages of monorepos
- ???? lerna 治理前端 packages 的最佳实际
- ???? 基于 lerna 和 yarn workspace 的 monorepo 工作流
- ???? Monorepos in the Wild
- ???? Monorepos: Please don’t!
- ???? Monorepo: please do!
- ???? Introduction to Lerna
- ???? monorepo 迁徙实际
7. ???? 扩大浏览
- 介绍实际 monorepo 生态:awesome-monorepo
- 一篇介绍 Google 如何将数十亿代码通过 monorepo 形式组织的论文:Why Google Stores Billions of Lines of Code in a Single Repository
- 一篇针对 Google 的调研报告,详尽地剖析了 monorepo 的优劣:Advantages and Disadvantages of a Monolithic Repository
8. ???? 招聘信息
阿里巴巴淘系用户增长团队 正在如饥似渴的寻找气味相投的搭档,如果您筹备好迎接适度的挑战,在让更多人喜爱手淘的同时,也让本人疾速成长,欢迎您发送简历至我的邮箱:kongtang.lb@alibaba-inc.com,我非常期待收到您的讯息。
- 封面图片起源:Photo by Tetiana SHYSHKINA on Unsplash
- 本文仅反对有偿转载,请分割作者洽谈转载费用