『前端工程』—— git子模块和fs-extra的应用

1,396 阅读7分钟

1、业务场景

入职新公司,接手了一个项目,该项目是引用一个SDK做应用开发。由于应用中一些定制化功能要去修改SDK源码才能实现,但是这个SDK是由另一个部门开发,没有这个SDK的发布权限,只有SDK源码git仓库的pull权限。

于是把SDK源码编译打包生成的SDK文件拷贝到应用项目代码文件夹中,然后在应用项目的代码中引用SDK文件中的index.js 来开发。

2、fs-extra的应用

fs-extra是一个文件操作相关工具库。

每次修改SDK源码后,要先编译打包生成SDK文件,再把SDK文件手动拷贝到应用项目代码文件夹中,这个过程也挺烦的。在加上SDK源码的git仓库没有push权限,修改的SDK源码也没有版本管理。于是把SDK源码和应用代码放在同一个文件夹中开发,并用同一个git仓库进行代码版本管理。其文件夹目录结构示意图如下所示:

其中 sdkcode/src 文件代表SDK源码文件,sdkcode/lib 文件代表SDK源码编译打包后生成的SDK文件。 appcode/src 文件代表应用代码文件, appcode/lib 文件代表拷贝过来的SDK文件。

那么可以利用fs-extra中的api来开发一个js脚本,执行后自动把 appcode 文件夹中的 lib 文件夹删除,然后把 sdkcode/lib 文件夹拷贝到 appcode/src 文件夹中,实现在应用项目中更新SDK。

把js脚本存放在 appcode 文件夹根目录下命名为 updataSDK.js,在 appcode 目录下执行 node development/updataSDK.js 命令即可,updataSDK.js 其中代码如下所示:

const fs = require('fs-extra');
const path = require('path');
/* libPath为appcode/lib文件的路径 */
const libPath = path.resolve(__dirname, './lib');
/* sdkLibPath为sdkcode/lib文件的路径 */
const sdkLibPath = path.resolve(__dirname, './lib');
/* 如果appcode/lib文件存在就把其删除*/
if (fs.existsSync(libPath)) {
  fs.removeSync(libPath);
}
/* 把appcode/lib文件拷贝到appcode文件夹下*/
fs.copySync(libPath, sdkLibPath);

3、开发过程的痛点

当SDK发布新版本后,若要去更新应用项目中的SDK源码,其操作流程如下所示:

  • 在SDK源码git仓库中以新版本对应的tag创建新分支后,拷贝SDK源码;

  • 在应用项目git仓库中创建内容为空白的新分支sdkcore,把SDK源码粘贴进去,提交分支;

  • 在应用项目git仓库中切换到开发分支devlop,去合并sdkcore分支,更新SDK源码;

  • 更新完成后,删除sdkcore分支。

以上更新SDK源码的模式在一个应用项目中应用还好,但是在多个应用项目中应用,就会出现以下几个痛点。

  • 1、每个应用项目的git仓库里面都包含SDK源码,导致git仓库体积庞大;

  • 2、在每个应用项目中去更新SDK源码,其中拷贝粘贴SDK源码会耗费大量时间,SDK源码有1.5G多;

  • 3、无法快速切换应用项目所依赖的SDK源码排查问题。

那么可以利用git子模块来解决以上所有的痛点。

4、git子模块的概念

把一个git仓库作为父仓库,在其中创建多个git仓库作为子仓库。这些子仓库就是git子模块,而父仓库就是git父模块。

子仓库的git操作不会影响到父仓库,比如提交子仓库的代码时不会把父仓库的代码提交上去,但是父仓库提交代码时,如果没用git把子仓库所在的文件夹忽略,会把子仓库中的代码提交到父仓库中。

5、git子模块的应用

把每个应用项目中的SDK源码抽离出来用一个git仓库来统一管理,把这个git仓库称为SDK仓库。在SDK仓库中以每个应用项目的名称创建分支,每个分支中的SDK源码对应各自应用项目中所依赖的SDK源码。

将每个应用项目创建对应的git仓库。然后把SDK仓库作为父仓库,也就是git父模块,然后在SDK仓库中把每个应用项目的仓库作为子模块添加进去,这样SDK源码和应用项目就关联起来。

以上的操作相当把每个应用项目的git仓库中SDK源码分离出来,每个应用项目的git仓库的体积就会大幅度减小,解决了开发过程的第一个痛点。

在SDK仓库中创建一个没有任何内容的空白分支,命名为updata分支并推送上去,在更新SDK源码中会用到。当SDK发布新版本了,在SDK仓库中以updata分支创建一个新分支,命名为SDK版本号。

在SDK源码git仓库中以新版本的tag创建新分支,下拉代码,拷贝SDK源码。把SDK源码粘贴到SDK仓库所在文件夹中,粘贴完成后提交SDK仓库,并推送上去。

后续如果由那个应用项目中的SDK源码想更新,就可以切到这个应用项目对应的SDK仓库分支,然后去合并对应SDK版本的分支,实现SDK源码的更新。这样只拷贝了一次SDK源码,而不是更新几个应用项目就要拷贝几次SDK源码,解决了开发过程的第二个痛点。

在开发应用a项目时,把SDK仓库切换到a分支,然后执行 updataSDK.js 脚本把SDK源码编译打包后生成的SDK文件拷贝到应用a项目中,updataSDK.js 脚本存放在每个应用项目的根目录中。

在后续开发过程中,应用a项目要用7.3.5版本的SDK源码排查一个BUG,就可以把SDK仓库切换到7.3.5分支(该分支的代码就是SDK源码仓库中的tag V7.3.5中的代码),然后执行 updataSDK.js 脚本把SDK源码编译打包后生成的SDK文件拷贝到应用a项目中,实现了快速切换应用项目所依赖的SDK源码排查问题,解决了开发过程的第三个痛点。

6、git实战操作

  • 在GitLab上新建一个仓库,命名为sdk_source_code,用来管理每个应用项目中的SDK源码,这里把这个git仓库称为SDK仓库。

  • 在确保已经安装好git的前提下,在D盘中点击鼠标右键,选择 Git Bash Here 菜单,打开git的命令行工具。

  • 执行 mkdir project 创建一个名为project的文件夹;

  • 执行 git clone SDK仓库的地址把SDK仓库克隆下来。

  • 克隆成功后,会在project的文件夹中生成一个 sdk_source_code 文件夹,执行 cd sdk_source_code,进入 sdk_source_code 文件夹中。

  • 执行 git checkout -b updatagit push --set-upstream origin updata,此时的master分支中还没有任何内容,基于它来创建一个新分支updata,并推送上去,用于后续更新SDK源码的操作。

  • 为了保存应用a项目中SDK源码的修改记录,要在应用a项目代码文件夹中执行 git checkout -b 应用a项目的名称,创建一个以应用a项目的名称,再把除SDK源码之外的代码都删掉后,执行 git remote set-url origin SDK仓库的地址git push,这样就把应用a项目中的SDK源码提交到SDK仓库中名为应用a名称的分支上。

  • 回到 sdk_source_code 文件夹中,执行 git submodule add 应用a项目的git仓库地址 应用a项目的名称,在SDK仓库中添加一个git子模块。添加成功后,会发现 sdk_source_code 文件夹中多了一个文件名为应用a项目的名称的文件夹,该文件夹中的代码就是应用a项目仓库中的代码。

  • 在SDK仓库中的 .gitignore 文件中添加 应用a项目的名称/,执行 git rm -r --cached .git add .git commit -m 'update .gitignore'git push,把应用a项目的代码从SDK仓库中忽略掉,这样提交SDK仓库时就不会把应用a项目的代码提交上去。

  • 最后要注意,因为应用在SDK仓库中把应用a项目的代码忽略掉。所以在其它地方克隆SDK仓库后,无法使用 git submodule init 来初始化子模块(克隆应用a项目的代码)。可以在SDK仓库所在文件夹的根目录上直接执行 git clone 应用a项目的git仓库地址 来初始化子模块。