人机交互爱好者的随笔

0%

Monorepo and CI

About

Monorepo

Monorepo 是一种项目的组织方式,许多开源项目均采用这种组织方式,如create-react-appreact-routerbabel,基本的项目结构如下

1
2
3
4
5
6
├── packages
| ├── pkg1
| | ├── package.json
| ├── pkg2
| | ├── package.json
├── package.json

Lerna

Lerna是一个 JavaScript 下用于管理 Monorepo 项目的工具。它通过配置文件以及 cli 命令的方式使用,优化了使用 git 和 npm 管理多包存储库的工作流。

Github Action

GithubAction 是 github 内置的一种 CI/CD 工具,它不需要项目安装 TravisCI、CircleCI 等 CI 工具即可使用 CI 功能。最重要的是:它对于不论是 private 还是 public 项目都是免费的。
GithubAction 有一个非常强大的功能——官方市场,在上面你可以搜索到其他开发者提交的 action,并在自己的 ci 脚本中使用。

Setup

创建基本项目结构

1
2
3
4
5
6
7
8
mkdir my-project && cd my-project
npm init -y # 创建根package.json
mkdir packages
mkdir packages/pkg1 && cd packages/pkg1 && npm init -y # 创建pkg1子项目
cd ../../
mkdir packages/pkg2 && cd packages/pkg2 && npm init -y # 创建pkg2子项目
cd ../../
yarn add -D lerna

初始化并配置 lerna

1
2
npx lerna init # 根目录生成 lerna.json 配置文件
vim lerna.json

修改 lerna.json 内容至如下

1
2
3
4
5
6
{
"packages": ["packages/*"],
"npmClient": "yarn", // 选择使用npm工具,默认为npm
"useWorkspaces": true, // 若npmClient设置为yarn,启用yarn的workspaces机制
"version": "0.0.0"
}

修改根 package.json

1
2
3
4
5
6
7
8
{
// ...
"private": true, // 使用workspaces机制必须将private设置为true
"workspaces": {
// 设置yarn workspaces包含的子项目
"packages": ["packages/*"]
}
}

react-router这样的项目,它的多个子项目分别以react-routerreact-router-domreact-router-config等名称单独发布到了 npm。而在子项目的实现代码中,难免出现互相依赖的,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// react-router/packages/react-router-config/modules/renderRoutes.js
import { Switch, Route } from "react-router";

function renderRoutes(routes, extraProps = {}, switchProps = {}) {
return routes ? (

{routes.map((route, i) => (

key={route.key || i}
path={route.path}
exact={route.exact}
strict={route.strict}
render={props =>
route.render ? (
route.render({ ...props, ...extraProps, route: route })
) : (

)
}
/>
))}
</Switch>
) : null;
}

此时需要将子项目间的依赖关系添加到所在项目package.jsondependenciesdevDependencies中,使得 lerna 在创建symlink时候可以将本地项目与node_modules下的依赖关联起来,否则会导致执行 build、test 等操作时报错。
lerna 在创建 symlink 时是通过npm/yarn提供的lin功能实现的。这样,在本地开发时,任何子项目内的改动都会同步到设置了对应 symlink 的其他子项目 node_modules 下

使 lerna 生效

执行以下命令即可使 lerna 的基本功能正常工作:

1
2
npx lerna bootstrap # 为各个子项目安装依赖,并根据package.json中的依赖配置创建symlink
npx lerna list # 查看本项目识别到的子项目名,以确定bootstrap操作是否成功

通过 lerna 批量操作

若要对所有子项目进行打包,可以通过lerna run < script >执行各个子项目 package.json 下的 script 命令,如 build、test。
若要清除所有子项目的node_modules,可以执行lerna clean命令。

创建 CI

Github Action 的 CI 采用YAML格式的文件进行配置,并将配置文件存放在./.github/workflows下。最基本的 ci 配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
name: CI

on: [push]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Run a one-line script
run: echo Hello, world!
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.

将配置文件修改为通过 lerna 执行 build、test,以验证项目的可用性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: setup
run: |
yarn
npx lerna bootstrap
- name: build
run: npx lerna run build
- name: test
run: npx lerna run test

功能完善

待续…

项目参考

Tan90Qian/leetcode:这是笔者看书时候顺手练习创建的项目,里面包含了 Monorepo、Lerna、Typescript、基于 rollup 的打包、基于 Jest 的单元测试、CI 等要素。

文章引用

  1. Monorepo——大型前端项目的代码管理方式
  2. Monorepo 是什么,为什么大家都在用?
  3. Lerna 中文教程详解
  4. 使用 lerna 管理大型前端项目
  5. Automating your workflow with GitHub Actions
  6. GitHub Actions 入门教程 - 阮一峰