目录
概述
本项目的 CI 配置包含以下核心功能:
🔍 检查项
| 检查项 | 触发时机 | 用途 |
|---|---|---|
| TypeScript 类型检查 | Pre-commit | 确保类型安全 |
| ESLint 代码规范 | Pre-commit | 代码风格和质量 |
| Prettier 代码格式化 | Pre-commit | 统一代码格式 |
| 提交消息规范 | Commit-msg | 规范化 Git 提交 |
| 分支保护 | Pre-commit | 防止直接提交到主分支 |
| 依赖自动安装 | Post-merge | 保持依赖同步 |
| 单元测试 | 手动/CI | 确保代码质量 |
📦 依赖包
json
{
"husky": "^9.1.5",
"lint-staged": "^15.2.9",
"@commitlint/cli": "^19.2.2",
"@commitlint/config-conventional": "^19.2.2",
"eslint": "^9.28.0",
"prettier": "^3.3.3",
"typescript": "^5.8.3",
"jest": "^29.7.0"
}
Git Hooks 配置
1. Husky 设置
安装和初始化
bash
# 安装依赖
pnpm add -D husky
# 初始化 husky
pnpm exec husky init
目录结构
bash
.husky/
├── _/ # Husky 内部文件
├── common.sh # 共享脚本
├── pre-commit # 提交前检查
├── commit-msg # 提交消息检查
└── post-merge # 合并后处理
2. Pre-commit Hook
文件:.husky/pre-commit
bash
. "$(dirname "$0")/common.sh"
echo "===\n>> Checking branch name..."
# 分支保护
if [[ -z $SKIP_BRANCH_PROTECTION ]]; then
BRANCH=$(git rev-parse --abbrev-ref HEAD)
PROTECTED_BRANCHES="^(main|master)"
if [[ $BRANCH =~ $PROTECTED_BRANCHES ]]; then
echo ">> Direct commits to the $BRANCH branch are not allowed."
exit 1
fi
fi
echo ">> Linting your files and fixing them if needed..."
# TypeScript 类型检查
pnpm type-check
# 代码规范检查和自动修复
pnpm lint-staged
功能:
- ✅ 阻止直接提交到
main/master分支 - ✅ 运行 TypeScript 类型检查
- ✅ 对暂存文件运行 ESLint 和 Prettier
3. Commit-msg Hook
文件:.husky/commit-msg
bash
pnpm commitlint --edit $1
功能:
- ✅ 验证提交消息格式符合 Conventional Commits 规范
4. Post-merge Hook
文件:.husky/post-merge
bash
function changed {
git diff --name-only HEAD@{1} HEAD | grep "^$1" >/dev/null 2>&1
}
echo 'Checking for changes in pnpm-lock.yaml...'
if changed 'pnpm-lock.yaml'; then
echo "📦 pnpm-lock.yaml changed. Installing dependencies..."
pnpm install
fi
echo 'You are up to date :)'
功能:
- ✅ 检测依赖变化,自动运行
pnpm install
5. Common Shell 脚本
文件:.husky/common.sh
bash
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Windows Git Bash 兼容性
if command_exists winpty && test -t 1; then
exec </dev/tty
fi
代码质量检查
1. Lint-staged 配置
文件:lint-staged.config.js
javascript
module.exports = {
// TypeScript/JavaScript 文件
'**/*.{js,jsx,ts,tsx}': (filenames) => [
`npx eslint --fix ${filenames
.map((filename) => `"${filename}"`)
.join(' ')}`,
],
// Markdown 和 JSON 文件
'**/*.(md|json)': (filenames) =>
`npx prettier --write ${filenames
.map((filename) => `"${filename}"`)
.join(' ')}`,
// 翻译文件特殊处理
'src/translations/*.(json)': (filenames) => [
`npx eslint --fix ${filenames
.map((filename) => `"${filename}"`)
.join(' ')}`,
],
};
功能:
- 只检查暂存的文件(提高性能)
- 自动修复可修复的问题
- 支持多种文件类型
2. Commitlint 配置
文件:commitlint.config.js
javascript
module.exports = {
extends: ['@commitlint/config-conventional'],
};
提交消息格式:
arduino
<type>: <description>
[optional body]
[optional footer]
允许的 type 类型:
| Type | 说明 | 示例 |
|---|---|---|
feat |
新功能 | feat: 添加用户登录功能 |
fix |
Bug 修复 | fix: 修复登录页面闪退问题 |
docs |
文档更新 | docs: 更新 API 文档 |
style |
代码格式(不影响功能) | style: 格式化代码缩进 |
refactor |
重构 | refactor: 重构用户服务模块 |
perf |
性能优化 | perf: 优化列表渲染性能 |
test |
测试相关 | test: 添加登录组件单元测试 |
chore |
构建/工具相关 | chore: 更新依赖版本 |
ci |
CI 配置 | ci: 添加 GitHub Actions 配置 |
build |
构建系统 | build: 优化打包配置 |
revert |
回滚提交 | revert: 回滚登录功能 |
3. ESLint 配置
文件:eslint.config.mjs
核心规则:
javascript
export default defineConfig([
// 全局忽略
globalIgnores([
'dist/*',
'node_modules',
'coverage',
'android',
'ios',
'.expo',
]),
// 核心规则
{
rules: {
'max-params': ['error', 3], // 最多3个参数
'max-lines-per-function': ['error', 300], // 函数最多300行
'unicorn/filename-case': [
'error',
{
case: 'kebabCase',
},
], // kebab-case 命名
'simple-import-sort/imports': 'error', // 自动排序 imports
'unused-imports/no-unused-imports': 'error', // 禁止未使用的导入
'import/no-cycle': ['error'], // 禁止循环依赖
'@typescript-eslint/consistent-type-imports': [
'warn',
{ prefer: 'type-imports' },
], // 强制使用 type imports
},
},
// TypeScript 特定配置
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: parser,
parserOptions: {
project: './tsconfig.json',
},
},
},
// 测试文件配置
{
files: ['**/__tests__/**/*', '**/*.test.*'],
plugins: { 'testing-library': testingLibrary },
},
]);
4. Prettier 配置
文件:.prettierrc.js
javascript
module.exports = {
singleQuote: true, // 使用单引号
endOfLine: 'auto', // 自动行尾符
trailingComma: 'es5', // ES5 尾随逗号
};
5. TypeScript 配置
文件:tsconfig.json
json
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true, // 严格模式
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"] // 路径别名
},
"esModuleInterop": true,
"checkJs": true // 检查 JS 文件
},
"exclude": ["node_modules", "android", "ios"]
}
6. Jest 配置
文件:jest.config.js
javascript
module.exports = {
preset: 'jest-expo',
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
testMatch: ['**/?(*.)+(spec|test).ts?(x)'],
// 代码覆盖率收集
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!**/coverage/**',
'!**/node_modules/**',
],
// 报告器
reporters: [
'default',
['github-actions', { silent: false }],
'summary',
[
'jest-junit',
{
outputDirectory: 'coverage',
outputName: 'jest-junit.xml',
},
],
],
// 路径映射
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
配置文件详解
Package.json Scripts
json
{
"scripts": {
// 代码检查
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"type-check": "tsc --noEmit",
"lint:translations": "eslint ./src/translations/ --fix --ext .json",
// 测试
"test": "jest",
"test:ci": "pnpm run test --coverage",
"test:watch": "pnpm run test --watch",
// 完整检查
"check-all": "pnpm run lint && pnpm run type-check && pnpm run lint:translations && pnpm run test",
// Git hooks
"prepare": "husky"
}
}
快速开始
在新项目中配置 CI
1. 安装依赖
bash
pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional
pnpm add -D eslint prettier typescript jest
pnpm add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
pnpm add -D eslint-plugin-prettier eslint-config-prettier
2. 初始化 Husky
bash
pnpm exec husky init
3. 创建配置文件
复制以下配置文件到项目根目录:
bash
# 必需的配置文件
├── .husky/
│ ├── pre-commit
│ ├── commit-msg
│ ├── post-merge
│ └── common.sh
├── lint-staged.config.js
├── commitlint.config.js
├── eslint.config.mjs
├── .prettierrc.js
├── tsconfig.json
└── jest.config.js
4. 添加 NPM Scripts
在 package.json 中添加:
json
{
"scripts": {
"prepare": "husky",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"type-check": "tsc --noEmit",
"test": "jest",
"check-all": "pnpm run lint && pnpm run type-check && pnpm run test"
}
}
5. 设置 Git Hooks 可执行权限
bash
chmod +x .husky/pre-commit
chmod +x .husky/commit-msg
chmod +x .husky/post-merge
6. 测试配置
bash
# 测试 lint
pnpm lint
# 测试类型检查
pnpm type-check
# 测试提交(会触发所有 hooks)
git add .
git commit -m "test: 测试 CI 配置"
提交代码流程
标准提交流程
bash
# 1. 确保在功能分支上
git checkout -b feat/your-feature-name
# 2. 添加修改的文件
git add .
# 3. 提交(使用规范的提交消息)
git commit -m "feat: 添加新功能"
# 自动触发:
# ✓ 分支检查
# ✓ TypeScript 类型检查
# ✓ ESLint 自动修复
# ✓ Prettier 格式化
# ✓ 提交消息格式验证
绕过检查(仅紧急情况)
bash
# 跳过分支保护
SKIP_BRANCH_PROTECTION=1 git commit -m "fix: 紧急修复"
# 跳过所有 pre-commit hooks
git commit --no-verify -m "fix: 紧急修复"
⚠️ 不推荐在正常开发中使用
常见问题
Q1: 提交时报错 "Direct commits to main branch are not allowed"
原因: 你在 main 或 master 分支上提交
解决方案:
bash
# 创建新分支
git checkout -b feat/your-feature
# 或者跳过检查(不推荐)
SKIP_BRANCH_PROTECTION=1 git commit -m "your message"
Q2: TypeScript 类型检查失败
原因: 代码存在类型错误
解决方案:
bash
# 查看具体错误
pnpm type-check
# 修复类型错误后重新提交
Q3: ESLint 错误无法自动修复
原因: 某些规则需要手动修复
解决方案:
bash
# 查看详细错误
pnpm lint
# 尝试自动修复
pnpm lint --fix
# 手动修复剩余问题
Q4: 提交消息格式错误
错误示例:
bash
git commit -m "add new feature" # ❌ 缺少 type
git commit -m "Add new feature" # ❌ 首字母大写
正确示例:
bash
git commit -m "feat: add new feature" # ✅
git commit -m "fix: resolve login issue" # ✅
Q5: Husky hooks 不生效
解决方案:
bash
# 重新安装 husky
rm -rf .husky
pnpm exec husky init
# 重新创建 hooks
# 复制配置文件到 .husky/
# 确保可执行权限
chmod +x .husky/*
Q6: 依赖没有自动安装
原因: post-merge hook 没有正确配置
解决方案:
bash
# 手动安装
pnpm install
# 检查 .husky/post-merge 是否存在
ls -la .husky/post-merge
最佳实践
✅ 推荐做法
-
永远在功能分支上工作
bashgit checkout -b feat/feature-name -
提交前本地测试
bashpnpm check-all -
编写清晰的提交消息
bashfeat: 用户认证功能 - 添加登录页面 - 实现 JWT token 验证 - 添加用户状态管理 -
小步提交,频繁提交
- 每个提交只包含一个逻辑变更
- 便于代码审查和回滚
-
定期运行完整检查
bashpnpm check-all
❌ 避免做法
- ❌ 频繁使用
--no-verify - ❌ 在 main 分支直接提交
- ❌ 不遵循提交消息规范
- ❌ 提交未格式化的代码
- ❌ 跳过类型检查和测试
维护和更新
定期任务
bash
# 每月更新依赖
pnpm update
# 检查过时的依赖
pnpm outdated
# 更新主要版本(谨慎)
pnpm update --latest
团队同步
bash
# 拉取最新代码后
git pull
# post-merge hook 会自动安装依赖
# 如果配置文件更新
pnpm install
总结
通过这套 CI 配置,你的项目将获得:
- ✅ 自动化代码质量检查
- ✅ 统一的代码风格
- ✅ 规范的提交历史
- ✅ 早期发现问题
- ✅ 更好的团队协作
这些配置可以直接应用于任何 React Native/Expo 项目,也可以根据项目需求进行调整。