项目结构探索——从无脑堆积到拆分再到合并(pnpm monorepo)

438 阅读4分钟

项目从无到有,从堆代码到拆分,再到合并,我们做了很多次探索,在探索的过程中不断优化项目架构,最终寻找一条最适合自己的道路。

1.0版本,业务代码全累加

项目开始初期,业务又少又简单,我们只是把代码堆上去,划分模块,其实就是在项目里建几个不同的文件夹而已。比较古老的JSP项目基本都是这样的结构,所有的代码都部署在同一个目录下,如下图,假设百度、GitHub、稀土掘金、慕课网都是我的JSP项目,我们会把这四个模块的代码全部放在一个Git仓库里,每次项目启动,都是运行了所有的代码。

截屏2024-07-21 22.07.12.png

我们也有意识地把一些公共的文件抽离成公共组件,类似JQuery,将其放到项目的公共文件夹,可供所有项目引用。

问题:

  • 随着业务变得非常多,项目启动、项目打包都变得十分耗时。(也可以单独启动某一个项目,但是必须要手动修改pom.xml文件);
  • 由于代码都是全累加的,所以不存在“增量更新”的概念,就算是改一个字,也要经过冗长的全量打包;

2.0版本,按业务拆分项目

当我们的项目大到一定规模时,我们维护起来非常不方便。当跑个代码或者打包都需要十几分钟甚至几十分钟时,我们就得考虑把项目拆成多个子项目,也可以用Vue、React重构一下。

如图,我们把项目按照模块去拆分。每一个菜单,都是一个独立的子项目。子项目可以独立运行,并且只需要提供一个跳转链接,配置在首页即可。登录状态同步只需要把所有项目用同一个域名和端口访问即可。

需要做的事情:

  • 针对每个模块,都新建一个项目(假设是Vue-Cli);

  • 使用Vue组件库;

  • 用rollup自己封装组件库,所有项目共用

这样1.0的两个大问题就解决了。

2.5版本,代码是拆开的,但是页面是合在一起的

也就是微前端的架构,把一个大项目拆分成多个独立灵活的小型应用,每个应用都可以独立开发、独立运行、独立部署,界面上展示的效果,是一个完整的应用。

重点技术:qiankun/wujie等等

  • 需要处理npm包版本的问题,公共组件修改之后对其他项目的影响,修改点同步;

  • 项目多了,git仓库维护的成本也高了;

  • 跨项目引用组件比较麻烦(webpack5的模块联邦可以实现),且难以维护。

2.5和2.0最大的区别就是多了一层项目的合并,使其看起来像是一个完整的系统。

截屏2024-07-28 22.06.47.png

如上图的效果,页面上有多个菜单,子菜单可以属于不同的业务模块,而代码是按照业务分开的。

3.0版本,在2.x的基础上,把代码合在一起

看到2.x把项目拆成好多个,我们又会面对新的问题:

  • 有些功能应该放在公共组件里,但是开发的成本大,要先修改公共组件,再去各个项目里使用,切换项目频繁;
  • Git仓库多,很难管理

为了解决这些问题,我们使用monorepo的架构,pnpm自带这个功能:

pnpm-workspace.yaml配置文件:

packages:
  - 'apps/*'
  - 'packages/*'

表示appspackages目录下各文件夹是独立的子工程,这些子工程可以独立操作发布。我们这里把业务代码放在app目录下,公共组件放在packages下。

项目目录结构:

apps
---pro-a
---pro-b
---pro-c
packages
---common
---------components
---------hooks
---------utils
package.json
pnpm-lock.yaml
pnpm-workspace.yaml

最外层的package.json

{
  "name": "@monorepo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@esbuild/win32-x64": "^0.23.0"
  }
}

子项目中定义:

{
  "@monorepo/common": "workspace:^",
}

业务代码里这样引用组件:

import { BasicTable } from '@monorepo/common/components/Table';

按照上面的写法,我们可以把项目都放到一个Git仓库里,维护起来更方便;另外公共组件的代码也在这个仓库里,不需要使用npm linkyalc等方法调试公共组件了。

总结:项目结构也是合久必分,分久必合,最终探索出一条最适合自己的道路,然后稳定下来。