本文将站在一个实习生的角度,分享笔者在 LogicFlow 中的实习经验和对于所遇问题的一些分析解决思路。本篇文章并非把实习总结一条条的罗列出来,而是把实习的经历和技术文章结合到一块儿,讲述实习生是如何在开源项目中快速成长的,与技术文章相比,阅读起来相对轻松。node
往前数算刚好一全年,当时大三的我刚刚加入春招大军,正在一场场面试中因被面试官拒绝而怀疑自我,又在一次次被拒后的自我反思中重拾自信,过了两个多月才在春招的末尾找到了第一份实习工做,随即跨越半个中国来到深圳的一家银行类公司,跟着师兄作了一些零零散散的小项目。在第一份实习中,最主要的收获仅仅是感觉到了职场与校园之间的一些差别,而在技术上,因为受到项目体量的限制,成长速度较为缓慢。第一份实习接近尾声时恰逢秋招伊始,或许是受益于第一段实习的经历,个人简历和面试都得到了不错的反馈,最终从手里的 offer 中选择了滴滴,校招也就此顺利收官。git
与滴滴签约后,想着早些熟悉一下之后的同事和项目,我提早来到北京实习。入职第一天,中午吃饭时从师兄口中得知,团队正在作一个开源项目(LogicFlow),我实习阶段的主要工做就是协助他们作一些开发。程序员
听到开源项目的时候,个人心里一颤,在潜意识里,开源项目开发难度大,且对开发者的技术水平要求高,自觉有些难以胜任,同时又以为异常幸运,历来没有想到能够在实习阶段遇上“造火箭”,将来会有大量的机遇推进我去学习新的知识,就这样带着一全年中最大的幸运开始了本身的实习生活。github
刚入职时,组内大佬们就已经完成了 LogicFlow 的核心功能以及对应文档,此时的 LogicFlow 还未开源,个人起步工做是为文档添加可操做的示例。面试
拿到内部仓库的访问权限后,我把代码下载到本地,粗略浏览了一下项目目录的大体结构:shell
LogicFlow
├── docs // 文档
├── examples // 示例
├── packages
│ ├── core // 核心包
│ │ ├── src
│ │ └── package.json
│ ├── extension // 拓展包
│ │ ├── src
│ │ └── package.json
│ └── site // 调试示例
│ ├── src
│ └── package.json
├── .commitlintrc.js
├── babel.config.js
├── eslintrc.js
├── .gitignore
├── lerna.json
├── package.json
├── developer.md
├── README.md
└── yarn.lock
复制代码
看完目录后我获取到了如下主要信息:npm
看完目录后肯定了下一步要作的事情:跟着 developer.md 为项目安装依赖。json
从 developer.md 中能够得知安装依赖的命令:bootstrap
npm run bootstrap
复制代码
执行完成以后,LogicFlow 的根目录和 examples、core、extension、site 目录下都多了一个 node_modules 文件夹,此时我产生了几个疑问:bash
好奇心驱使我查看了 npm run bootstrap 中的原始命令,在根目录的 package.json 中,bootstrap 是这样定义的:
{
"scripts": {
"bootstrap": "yarn && lerna bootstrap",
}
}
复制代码
很明显,npm run bootstrap
先经过 yarn 根据根目录的 package.json 为项目安装了全局依赖,而后经过 lerna bootstrap 为 examples、core、extension 和 site 各自安装了依赖。
到目前为止,我能够肯定 LogicFlow 使用 lerna 这个东西对项目进行了工程化管理,lerna 支持了一个项目中能够存放多个子项目,同时 lerna 对我来讲是一个新的知识盲点。
带着疑惑,找到了 lerna 的代码仓库,在官方 README.md 中,我快速捕捉了如下关键信息:
同时找到了 lerna 的核心命令 lerna bootstrap,它主要完成了如下内容:
软链关系以下:
/node_modules
/examples
└── node_modules
├── @logicflow/core --> /packages/core // 软链
└── @logicflow/extension --> /packages/extension // 软链
/packages
├── core
│ └── node_modules
├── extension
│ └── node_modules
│ └── @logicflow/core --> /packages/core // 软链
└── site
└── node_modules
├── @logicflow/core --> /packages/core // 软链
└── @logicflow/extension -> /packages/extension // 软链
复制代码
如今就能够解释以前的几个疑问了:
已经知道,各个包之间能够直接引用本地的最新代码进行开发,如今咱们应该在启动项目以前,先把各个包构建一下以便其余包引用,如 developer.md 中的构建命令:
# 先构建类型
# LogicFlow 使用 TS 进行开发,不一样的包之间存在类型依赖
npm run build:types
# 构建源码
npm run build
复制代码
在根目录执行完上面两个命令以后,就能够进入 examples 目录进行开发调试了:
cd examples
npm run start
复制代码
到了 LogicFlow 开源时,项目的多包管理形式发生了新的变化。在 LogicFlow 正式发布的过程当中,师兄添加了一个 yarn workspaces 的功能,这一样又触及到了个人知识盲区。
有了 yarn workspaces 以后,package.json 发生了变动:
{
"workspaces": ["packages/*", "examples"],
"scripts": {
"bootstrap": "yarn",
}
}
复制代码
在 package.json 中新增了一个 workspaces 的字段,而 npm run bootstrap 命令只经过执行 yarn 来安装依赖。安装依赖以后,与添加 yarn workspace 以前相比,惟一不一样的点来自于各个包的 node_modules 内部,即各个包中若是有相同的依赖,那么这些依赖会被提取到根目录下的 node_modules 中,而整个项目在本地的体积就会大大缩小。
例如,在 core、extension、examples、site 这四个包中都使用了 @babel/core 这个工具,那么 @babel/core 就会被提取到根目录下的 node_modules 中,而那四个包的 node_modules 目录就缩减了下来。
/node_modules
├── @babel/core
├── @logicflow/core --> /packages/core // 软链
└── @logicflow/extension --> /packages/extension // 软链
/examples
└── node_modules
/packages
├── core
│ └── node_modules
├── extension
│ └── node_modules
└── site
└── node_modules
复制代码
与添加 yarn workspaces 以前相比,最重要的一点是软链(symlink)的功能保存了下来,到此为止,这个 yarn workspaces 又让我产生了新的疑惑:
带着这几个疑问,又开始了新的探索。
一样的,我找到了 yarn 对 workspaces 的介绍,文档中表示,yarn workspaces 可以完成如下任务:
也就是说,yarn workspaces 一样也是一个 monorepo 的管理工具,可是它所提供的功能仅仅与 lerna 提供的底层功能同样,为本地相互依赖的包创建软链,并在此基础上进行优化,将各个包的共同依赖抽离出来到根目录。
yarn workspaces 除了提供 lerna 的底层功能之外,其余高级功能均不支持,这就是为何有了 yarn workspaces 以后,LogicFlow 仍然保留 lerna 的缘由:
因此,针对于 monorepo 的形式,咱们能够同时使用 workspaces 和 lerna 来进行项目管理。另外,在 npm 7.x 版本中也已经支持了 workspaces 功能。
从刚加入 LogicFlow 时,项目就已经开始使用 monorepo 的管理形式了,那么就会有对应的疑问,LogicFlow 为何要用 monorepo 呢,它的优势在哪里,它有没有什么缺点呢?
以 LogicFlow 为例,我总结了 monorepo 为项目带来的一些优势:
monorepo 能够保证 extension 直接引用到本地 core 的最新代码,若是是 multirepo 的形式,须要先通过 core 的发包,而后在 extension 中下载使用。
monorepo 能够在开发过程当中省去对 core 包的频繁发版与安装。
monorepo 能够一次为多个包安装依赖,若是是 multirepo,须要为每一个项目都安装一次依赖。
使用前文中的 workspaces,还能够将相同的依赖从各个包中抽离出来,减小整个项目在本地的体积。
在 LogicFlow 中,extension 依赖于 core 的代码,当 core 发生变动后,extension 经常也要随之改变,为了保证这两个包之间的依赖关系清晰稳定,LogicFlow 始终保持二者的版本号一致,这就须要同步地快速发版,monorepo 能够保证同时对多个包进行操做。
实际上,monorepo 的优势基本是由各类工具在 monorepo 的基础上带来的,其 monorepo 自己也存在缺点。
在 monorepo 中进行多个包的开发、联调、上线时,仍然须要执行屡次打包或上线的命令,例如,当 LogicFlow 的 core 和 extension 发生变更后,对应的 examples 也会变化,这就须要先分别对 core 和 extension 进行打包,而后供 examples 的开发使用,因此 monorepo 的每个动做包含了多个项目的步骤,使得管理成本上升。
解决方案:引入 lerna 来管理 monorepo,能够实现对多个包的同时构建或上线等。
当全部的包都放到一个项目里,安装依赖以后整个项目的体积会变大,多个类似的 node_modules 会使得项目体积飙升。
解决方案:使用 workspaces 将不一样包中相同的依赖安装到根目录下,以便依赖的复用。
在一个 git repository 中修改多个包的代码,会致使多个包的 commits 掺杂在一块儿,在查看 commit log 的过程当中会增长分析成本。
解决方案:规范 commit 格式,在 commit 中注明改动所属的包,例如:fix(core): something。
多个包放到同一个仓库中意味着它们的访问权限必须是一致的,对于 LogicFlow 这种开源项目并无影响,但当某些项目拥有不一样访问权限的包时,monorepo 并不适用。
每一个程序员都会懂得,职业生涯中可以有一个好的项目做为磨练本身的机会是很是可贵的,开源项目脱离了业务需求中逻辑的重复性和复杂性,保留了对行业内各类前沿技术的应用,是让开发者快速成长的好机会。可以有机会加入 LogicFlow,对我这个实习生而言是很是幸运的,如同作梦同样,在 LogicFlow 中所遇到的每个疑问和难题,都像是有位老师在指引我前行。
本篇文章以一个实习生的视角,讲述了在第一次面对开源项目 LogicFlow 时所遇到的“新概念” - monorepo,并分享了笔者对于 monorepo 学习和理解,monorepo 自己瑕不掩瑜,是开源项目能够考虑使用的一种包的管理形式,在后面的实习阶段,笔者还会将其余所遇到的有意思的新挑战分享给你们。
更多阅读资料: