模块化与组件化
最近一直在研究客户端的组件化/模块化问题,除了将项目拆分为多个小的子模块,还会涉及到多个子模块管理的问题。下面说一些在模块化开发中的一些基本知识。
一个完整的模块化大型项目,从低到高依次是基础层、 业务层和宿主层,可以根据项目的规模和开发人员的数量拆分成多个子工程协同开发。
宿主层
宿主层位于最上层, 主要作用是作为一个 App 壳, 将需要的模块组装成一个完整的 App, 这一层可以管理整个 App 的生命周期(比如 Application 的初始化和各种组件以及三方库的初始化)。
基础层
业务层位于中层, 里面主要是根据业务需求和应用场景拆分过后的业务模块, 每个模块之间互不依赖, 但又可以相互交互, 比如一个电商App由 搜索、订单、购物车、支付等业务模块组成,且模块之间可以相互调用。
说明:每个业务模块都可以拥有自己独有的 SDK 依赖和自己独有的 UI 资源 (如果是其他业务模块都可以通用的 SDK 依赖 和 UI 资源 就可以将它们抽离到 基础 SDK(CommonSDK 和 UI 组件(CommonRes ) 中。
业务层
基础层位于最底层, 里面又包括 核心基础业务模块、公共服务模块、 基础 SDK 模块, 核心基础业务模块 和 公共服务模块 主要为业务层的每个模块服务, 基础 SDK 模块 含有各种功能强大的团队自行封装的 SDK 以及第三方 SDK, 为整个平台的基础设施建设提供动力。
Git Submodule
Git Submodule 允许一个git仓库,作为另一个git仓库的子目录,并且保持父项目和子项目相互独立。
常用命令
git submodule涉及的常用功能有:
- git clone <
repository
> –recursive :递归的方式克隆整个项目 - git submodule add <
repository
> <path
> :添加子模块 - git submodule init :初始化子模块
- git submodule update :更新子模块
- git submodule foreach git pull: 拉取所有子模块
使用
创建带子模块的项目
例如,现在我们要创建一个如下结构的项目。
代码语言:javascript复制project
|--moduleA
|--readme.txt
依次使用下面的命令,创建project版本库,并提交readme.txt文件。
代码语言:javascript复制git init --bare project.git
git clone project.git project1
cd project1
echo "This is a project." > readme.txt
git add .
git commit -m "add readme.txt"
git push origin master
cd ..
然后,创建moduleA版本库,并提交a.txt文件。
代码语言:javascript复制git init --bare moduleA.git
git clone moduleA.git moduleA1
cd moduleA1
echo "This is a submodule." > a.txt
git add .
git commit -m "add a.txt"
git push origin master
cd ..
在project项目中引入子模块moduleA,并提交子模块信息。
代码语言:javascript复制cd project1
git submodule add ../moduleA.git moduleA
git status
git diff
git add .
git commit -m "add submodule"
git push origin master
cd ..
使用命令git status
可以看到多了两个需要提交的文件,其中.gitmodules
指定submodule
的主要信息,包括子模块的路径和地址信息,moduleA
指定了子模块的commit id
,使用git diff
可以看到这两项的内容。
需要注意的是,父项目的git并不会记录submodule的文件变动,它是按照commit id指定submodule的git header,所以.gitmodules和moduleA这两项是需要提交到父项目的远程仓库的。
代码语言:javascript复制On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: moduleA
克隆带子模块的版本库
方法一
先clone父项目,再初始化submodule,最后更新submodule,初始化只需要做一次,之后每次只需要直接update就可以了,需要注意submodule默认是不在任何分支上的,它指向父项目存储的submodule commit id。
代码语言:javascript复制git clone project.git project2
cd project2
git submodule init
git submodule update
cd ..
方法二
采用递归参数–recursive,需要注意同样submodule默认是不在任何分支上的,它指向父项目存储的submodule commit id。例如:
代码语言:javascript复制git clone project.git project3 --recursive
修改子模块
修改子模块之后只对子模块的版本库产生影响,对父项目的版本库不会产生任何影响,如果父项目需要用到最新的子模块代码,我们需要更新父项目中submodule commit id,默认可以使用git status就可以看到父项目中submodule commit id已经改变了,我们只需要再次提交就可以了。
代码语言:javascript复制cd project1/moduleA
git branch
echo "This is a submodule." > b.txt
git add .
git commit -m "add b.txt"
git push origin master
cd ..
git status
git diff
git add .
git commit -m "update submodule add b.txt"
git push origin master
cd ..
更新子模块
更新子模块的时候要注意子模块的分支默认是不是master分支。
方法一
先pull父项目,然后执行git submodule update,注意moduleA的分支始终不是master。
代码语言:javascript复制cd project2
git pull
git submodule update
cd ..
方法二
先进入子模块,然后切换到需要的分支,这里是master分支,然后对子模块pull,这种方法会改变子模块的分支。
代码语言:javascript复制cd project3/moduleA
git checkout master
cd ..
git submodule foreach git pull
cd ..
删除子模块
删除子模块会涉及到以下几个步骤:
- 删除.gitsubmodule里相关部分;
- 删除.git/config 文件里相关字段;
- 删除子仓库目录。
网上有好多使用的是下面的这种方法:
代码语言:javascript复制git rm --cached moduleA
rm -rf moduleA
rm .gitmodules
vim .git/config
然后提交到远程服务器:
代码语言:javascript复制git add .
git commit -m "remove submodule"