如何构建一个基本的monorepo架构的大型前端项目

3

主题

5

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2022-12-13 08:45:53 | 显示全部楼层
背景——面对项目中的痛点如何用monorepo来解决

相信看到这篇文章的同学应该或多或少的对monorepo架构有些了解了,这里呢我也不讨论什么是monorepo了(网上很多),我们直奔主题。
采用痛点加解决方案的方式来搭建一个基本的monorepo结构的项目
简单说明,为什么要用monorepo

其实在我们在日常开发中,尤其是稍微大一点的项目
比如一个前端团队要去接多个后端,可能要同时维护几个项目,这样当我们来了一个新人的时候,要安排人手去带新来的同事,这里其实并不是技术上或者是业务上需要学习的多,而是有很多隐藏的部落知识(Tribe Knowledge)并没有落实到文档,被记录下来,而是分散在各个项目中,需要有人手把手教才可以。
这些知识,包括但不限于:

  • 怎么把项目的所有依赖从网上拉下来
  • 配置好开发环境并可以干活
  • 哪些配置不可以修改和提交
  • 为什么这一块要用祖传的依赖版本
  • ......
这些让人头疼的问题,可能只掌握在当时的开发手里,而且很难落实成文档,不但让新人需要更长时间去适应项目而且还会造成这部分信息的流失。
其实这个问题,在大型项目中还只是其中一个痛点,我们面临的问题远不止如此
这些问题在monorepo架构下,基本上都得到了解决
那monorepo这个方案是如何解决这个问题呢?带着这个问题,我们一起探索一下monorepo
一、如何快速地构建一个monorepo结构的项目

在解决问题前我们先简单地搭建一个monorepo项目,对于搭建这种多项目的架构我们需要一个管理工具,这个工具我们选择使用lerna
为什么要选择lerna呢?

在选框架的时候,如果功能或者业务上没有什么特殊要求我会遵循几个优先级的条件:
1、开源协议,这个不多说了,给项目引入法务风险是绝对不可以的
2、Start数量 这个也很简单,start不多的肯定不好,这个我会在几个相同框架下取个平均值,做个判断
3、开发者 知名团队 > 知名个人 > 一般开发者
4、文档:主要是README和相关文档网站,ps:一个文档都写不好的框架,呵呵~
5、更新时间:一个几个月不更新的项目大概率是作者跑路了
6、社区:群、社区网站、Issues的活跃程度
以上几点可以综合考虑一下,当然如果项目着急或者觉得调研比较麻烦,我们还有plan B,就是别人用啥我们用啥
就像现在,前端开发都会无脑选个vue或者react一样,不需要做上面的调研,直接开始
需要调研的同学可以按照上面的步骤,去lerna的git地址去看一下,lerna还是很优秀的~
我们采用这个工具的主要原因是,最近在看几个低代码框架的源代码,都采用了lerna,像百度amis,阿里的lowcode-engine、formily。
构建monorepo项目

首先是全局安装lerna
npm install --global lerna新建一个文件夹 名字任意,在文件夹中执行
git init
lerna init执行完毕会得到,这样几个目录



lerna 初始项目

目前来说,这还是一个空项目,为了方便后面做一些测试,我们这里用命令创建四个项目,在创建之前,我们先看一lerna.json这个文件



lerna.json

比较需要关注的是这个的配置,如果各位同学不想用packages目录作为项目代码的目录可以修改,当然了lerna.json还有一些其他的配置,有兴趣的可以去看文档,这里就不展开了。
执行
lerna create <name>这里我创建了四个项目,各位同学可以少创建一点,创建完毕后我们在每个项目下面在新建个src目录用来存放,各个项目的业务代码,大概是这个样子。



项目目录

这里简单介绍一下目录:

  • lib是用来保存编译后的代码的,给别的库引用
  • src用来存放工程文件,即项目代码
  • __tests__文件目录是用来保存单元测试文件的。
好的到此一个基本的Monorepo结构的项目就搭建起来了
二、前端脚手架,前端的另外一个坑

脚手架作为前端工程化中,工具链中的一个重要环节,相信很多同学都使用过,知名的有vite、create-react-app、next等,这些脚手架为我们提供了基本开发外,也带来了一些问题:
问题一、年初我们用现成的脚手架启动了一个新项目的开发,到了年中,随着公司技术基建的推进和技术规范的推出我们更新了脚手架,之后用这个新的脚手架又创建了一个项目进行业务开发
此时,年初的项目大概率就会被忘了(ps:反正也稳定运行了,就假装忘了吧)做更新,这两个项目就会产生差异,而这些差异的信息大概率会变为隐患,直到某一个时间爆发。
问题二、由于配置分散在各个项目中,无法限制一些文件的修改,如husky,.eslintrc,.gitignore,.gitattributes,.commitlintrc,.cz-config,tsconfig这些文件,可以在使用脚手架后随意修改,因为不加限制能更快的开发业务,劣币驱逐良币,让规范形同虚设。
简单分析一下,什么原因造成这些问题的:

  • 代码更新不及时或很难更新
  • 配置代码没有权限控制
  • 规范推行后没有有效的检查手段,靠自觉和人工检查
如何解决:

  • 把框架做成一个在monorepo项目中的子项目
  • 使用git-submodule让框架项目,使用单独的git仓库管理,设置读写权限
既然想到了这些方案,我们不妨在上面创建好的monorepo项目中实践一下,首先我们新创建个项目front-end_engineering,把之前项目里的front-end_engineering文件夹删除
1、新建文件夹front-end_engineering,并进入
2、执行 git init
3、执行 npm init
4、在github上创建一个同名项目,如图



github创建项目

5、把这个项目推送上去,如图搞完就是这个样子



github项目目录

6、使用git-submodule把项目引入到上面创建的monorepo项目中,在根目录执行
git submodule add <项目的git地址>  packages/<项目名称>


submodule的执行结果

一切顺利的话我们会得到这样一个结果,然后我们用另一个编辑器,打开front-end_engineering 这个项目
7、在 front-end_engineering这个项目中创建,这几个文件,修改package.json的script


修改index.js,简单的写个脚本将两个git的配置文件,复制到form-lowcode的根目录下,代码如下:
et fs = require('fs')
let path = require('path')
// console.log(`当前文件路径是:${__dirname}`)

if (__dirname.indexOf("package") !== -1) {
    copyGitattributes()
    copyGitignore()
}else{
    console.warn("没有在monorepo项目中执行")
}
function copyGitattributes() {
    //路径问题不要太纠结先实现基本功能
    let fromPath = path.join(__dirname, ".gitattributes")
    let toPaht = path.join(__dirname, "..", "..", "..", ".gitattributes")
    fs.readFile(fromPath, (err, data) => {
        fs.writeFile(toPaht, data, (err, deta) => {
            if (err) {
                throw (err)
            }
        })
    })
}
function copyGitignore() {
    //路径问题不要太纠结先实现基本功能
    let fromPath = path.join(__dirname, ".gitignore")
    let toPaht = path.join(__dirname, "..", "..", "..", ".gitignore")
    fs.readFile(fromPath, (err, data) => {
        fs.writeFile(toPaht, data, (err, deta) => {
            if (err) {
                throw (err)
            }
        })
    })
}8、写完在monorepo项目中,拉取新代码后, 执行 lerna run git_int,就会将两个文件复制到项目中了,当然了其他的配置文件也可以如此操作,我们还可以接收命令行参数,做更多的功能优化。



执行脚本后的结果

到此,我们对问题二简单总结一下,首先front-end_engineering在form-lowcode这个项目中究竟是个什么状态呢,这里我截个图,是以软链接形式存在的。



git-submodule存在的状态

其次,由于front-end_engineering是单独的项目,我们可以在git上限制读写权限,有效的避免代码被修改,之后还可以在push或者部署阶段加入测试(如执行front-end_engineering)中的某个脚本去校验实际项目,防止配置文件被生成后,人为手动修改。
最后,配置文件只需要做到根路径,达到最小使用标准,各端的开发依旧可以在子包中加入自己的配置,不影响拓展性。
总结

OK到此,我们有了monorepo的项目,也创建了一些业务文件夹,还把前端工程化实现的方案也整合到了项目中,可以愉快的写代码了。
预告一下,接下来,我准备用游戏开发中的ECS架构,写一个简单的 表单低代码项目。有了明显进度后会第一时间分享的哦~敬请关注
回复

举报 使用道具

您需要登录后才可以回帖 登录 | 立即注册
快速回复 返回顶部 返回列表