Monorepo 开发工作流实践:本地开发、调试与发布流程

约 12 分钟阅读

前言

开发工作流是 Monorepo 项目中的关键环节。如何高效地进行本地开发,如何调试跨包代码,如何管理代码规范,如何发布包到 npm,是每个 Monorepo 项目必须解决的问题。

本文以 Vue Ace Admin 项目为例,详细介绍 Monorepo 中的开发工作流实践。

如果你还不熟悉 Monorepo 基础配置,建议先阅读:

本地开发流程

workspace 协议的工作原理

在本地开发时,主应用通过 workspace:* 直接使用源码:

json
// package.json
{
  "dependencies": {
    "@codexlin/ace-admin-hooks": "workspace:*",
    "@codexlin/ace-admin-ui": "workspace:*"
  }
}

pnpm 自动创建符号链接:

bash
node_modules/@codexlin/ace-admin-hooks -> packages/hooks
node_modules/@codexlin/ace-admin-ui -> packages/ui

优势:

  • ✅ 直接使用源码,修改立即生效
  • ✅ 无需构建,开发效率高
  • ✅ 完整的 TypeScript 类型支持
  • ✅ Vite HMR 自动热更新

开发工作流示例

场景:修改 ProTable 组件

  1. 修改包代码

    typescript
    // packages/ui/src/pro-table/ProTable.vue
    // 添加新功能或修复 bug
    
  2. 主应用自动更新

    • Vite HMR 检测到文件变更
    • 自动重新编译
    • 浏览器自动刷新
    • 无需手动操作
  3. 类型检查

    • TypeScript 直接从源码读取类型
    • IDE 提供完整的类型提示
    • 类型错误立即显示

开发命令

bash
# 启动主应用开发服务器
pnpm dev

# 开发 UI 包(watch 模式)
pnpm dev:ui

# 开发文档站点
pnpm dev:docs

并行开发:

bash
# 终端 1:开发主应用
pnpm dev

# 终端 2:开发 UI 包
pnpm dev:ui

# 修改 UI 包代码,主应用自动更新

调试技巧

1. 查看包链接状态

bash
# 查看 workspace 包链接
pnpm list @codexlin/ace-admin-ui

# 输出示例:
# @codexlin/ace-admin-ui 0.3.0
# └── workspace:packages/ui

2. 重新链接包

如果包链接出现问题:

bash
# 重新安装依赖
pnpm install

# 或删除 node_modules 重新安装
rm -rf node_modules
pnpm install

3. 调试包代码

使用 VS Code 调试:

.vscode/launch.json

json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Debug Vue App",
      "url": "http://localhost:5173",
      "webRoot": "${workspaceFolder}/src",
      "sourceMaps": true
    }
  ]
}

在包代码中打断点:

  • 直接在 packages/ui/src/ 中打断点
  • 调试器会自动映射到源码
  • 支持单步调试和变量查看

4. 类型检查

bash
# 检查所有包的类型
pnpm type-check

# 检查特定包
cd packages/ui
pnpm type-check

代码规范管理

ESLint 配置

根目录 ESLint 配置:

typescript
// eslint.config.ts
import { defineConfig } from 'eslint-define-config'

export default defineConfig({
  root: true,
  extends: [
    'plugin:vue/vue3-recommended',
    '@vue/typescript/recommended'
  ],
  rules: {
    // 统一规则
  }
})

所有包共享配置:

  • 统一的代码风格
  • 统一的错误检查
  • 统一的格式化规则

Prettier 配置

.prettierrc.json

json
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5"
}

格式化命令:

bash
# 格式化所有代码
pnpm format

# 格式化特定包
pnpm -C packages/ui format

Git Hooks

使用 simple-git-hooks:

json
{
  "simple-git-hooks": {
    "pre-commit": "npx lint-staged",
    "commit-msg": "npx commitlint -e $1"
  }
}

lint-staged 配置:

json
{
  "lint-staged": {
    "src/**/*.{ts,vue}": [
      "eslint --fix",
      "prettier --write"
    ]
  }
}

工作流程:

  1. 提交代码前自动运行 lint-staged
  2. 只检查暂存的文件
  3. 自动修复可修复的问题
  4. 提交信息必须符合规范

Git 工作流

分支策略

主分支:

  • main:生产环境代码
  • develop:开发环境代码

功能分支:

  • feat/xxx:新功能
  • fix/xxx:bug 修复
  • refactor/xxx:重构

提交规范

使用 Conventional Commits:

bash
# 新功能
git commit -m "feat(ui): 添加 ProTable 排序功能"

# Bug 修复
git commit -m "fix(hooks): 修复 useList 分页问题"

# 文档更新
git commit -m "docs: 更新 README"

# 重构
git commit -m "refactor(ui): 重构 ProButton 组件"

提交格式:

text
<type>(<scope>): <subject>

<body>

<footer>

类型说明:

  • feat:新功能
  • fix:bug 修复
  • docs:文档更新
  • style:代码格式
  • refactor:重构
  • test:测试
  • chore:构建/工具

代码审查流程

  1. 创建功能分支

    bash
    git checkout -b feat/new-feature
    
  2. 开发并提交

    bash
    git add .
    git commit -m "feat: 新功能"
    git push origin feat/new-feature
    
  3. 创建 Pull Request

    • 描述变更内容
    • 关联相关 Issue
    • 等待代码审查
  4. 合并到主分支

    • 通过审查后合并
    • 自动触发 CI/CD

npm 发布流程

发布前准备

1. 更新版本号

bash
# 使用 npm version
npm version patch  # 1.0.0 -> 1.0.1
npm version minor  # 1.0.0 -> 1.1.0
npm version major  # 1.0.0 -> 2.0.0

2. 构建包

bash
# 构建 hooks 包
pnpm build:hooks

# 构建 UI 包
pnpm build:ui

3. 检查构建产物

bash
# 检查 dist 目录
ls packages/ui/dist/

# 应该包含:
# - ace-admin-ui.es.js
# - ace-admin-ui.umd.js
# - ace-admin-ui.css
# - types/

发布到 npm

1. 登录 npm

bash
npm login

2. 发布包

bash
# 发布 hooks 包
cd packages/hooks
pnpm publish

# 发布 UI 包
cd packages/ui
pnpm publish

3. 验证发布

bash
# 检查 npm 上的包
npm view @codexlin/ace-admin-ui

# 安装测试
pnpm add @codexlin/ace-admin-ui@latest

自动化发布脚本

发布脚本示例:

javascript
// scripts/publish.js
import { execSync } from 'child_process'

const packages = ['hooks', 'ui']

packages.forEach(pkg => {
  console.log(`Building ${pkg}...`)
  execSync(`pnpm -C packages/${pkg} build`, { stdio: 'inherit' })
  
  console.log(`Publishing ${pkg}...`)
  execSync(`pnpm -C packages/${pkg} publish`, { stdio: 'inherit' })
})

使用方式:

bash
node scripts/publish.js

实际开发场景

场景一:添加新 Hook

步骤:

  1. 创建 Hook 文件

    typescript
    // packages/hooks/src/useNewHook.ts
    export function useNewHook() {
      // 实现逻辑
    }
    
  2. 导出 Hook

    typescript
    // packages/hooks/src/index.ts
    export { useNewHook } from './useNewHook'
    
  3. 在主应用中使用

    typescript
    // src/views/SomeView.vue
    import { useNewHook } from '@codexlin/ace-admin-hooks'
    
    const { ... } = useNewHook()
    
  4. 立即生效

    • Vite HMR 自动更新
    • 无需重新构建

场景二:修改 UI 组件

步骤:

  1. 修改组件代码

    vue
    <!-- packages/ui/src/pro-table/ProTable.vue -->
    <template>
      <!-- 修改模板 -->
    </template>
    
  2. 更新类型定义

    typescript
    // packages/ui/src/pro-table/type.ts
    export interface ProTableProps {
      // 更新类型
    }
    
  3. 主应用自动更新

    • 组件变更立即反映
    • 类型错误立即显示

场景三:跨包调试

问题: UI 包使用 hooks 包,如何调试?

解决方案:

  1. 在 hooks 包打断点

    typescript
    // packages/hooks/src/useList.ts
    export function useList() {
      debugger  // 断点
      // ...
    }
    
  2. 在 UI 包调用

    typescript
    // packages/ui/src/pro-table/ProTable.vue
    import { useList } from '@codexlin/ace-admin-hooks'
    
    const { ... } = useList()  // 会触发 hooks 包的断点
    
  3. 调试器自动映射

    • 支持跨包调试
    • 完整的调用栈

CI/CD 集成

GitHub Actions 示例

.github/workflows/ci.yml

yaml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 10.14.0
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: 'pnpm'
      
      - run: pnpm install
      - run: pnpm type-check
      - run: pnpm lint
      - run: pnpm build

自动发布流程

yaml
name: Publish

on:
  push:
    tags:
      - 'packages/ui/v*'
      - 'packages/hooks/v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v3
        with:
          registry-url: 'https://registry.npmjs.org'
      
      - run: pnpm install
      - run: pnpm build
      - run: pnpm publish --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

最佳实践总结

1. 开发流程

  • ✅ 使用 workspace:* 进行本地开发
  • ✅ 利用 Vite HMR 实现热更新
  • ✅ 使用 TypeScript 进行类型检查
  • ✅ 定期运行 lint 和 format

2. 调试技巧

  • ✅ 使用 VS Code 调试器
  • ✅ 在源码中打断点
  • ✅ 利用浏览器 DevTools
  • ✅ 查看包链接状态

3. 代码规范

  • ✅ 统一的 ESLint 配置
  • ✅ 统一的 Prettier 配置
  • ✅ 使用 Git Hooks 自动检查
  • ✅ 遵循提交规范

4. 发布流程

  • ✅ 更新版本号
  • ✅ 构建包
  • ✅ 检查构建产物
  • ✅ 发布到 npm
  • ✅ 验证发布结果

常见问题与解决方案

Q1: 修改包代码后主应用不更新

问题: 修改了包代码,但主应用没有更新

解决方案:

  1. 检查包链接

    bash
    pnpm list @codexlin/ace-admin-ui
    
  2. 重启开发服务器

    bash
    # 停止当前服务器
    # 重新启动
    pnpm dev
    
  3. 清除缓存

    bash
    rm -rf node_modules/.vite
    pnpm dev
    

Q2: 类型错误但代码能运行

问题: TypeScript 报错,但代码能正常运行

解决方案:

  1. 检查 tsconfig.json 配置
  2. 确保类型文件已生成
    bash
    pnpm build:hooks
    pnpm build:ui
    
  3. 重启 TypeScript 服务器(VS Code)

Q3: 发布失败

问题: npm publish 失败

解决方案:

  1. 检查登录状态

    bash
    npm whoami
    
  2. 检查包名是否已存在

    bash
    npm view @codexlin/ace-admin-ui
    
  3. 检查版本号

    bash
    # 确保版本号递增
    npm version patch
    

总结

Monorepo 的开发工作流需要综合考虑多个方面:

  1. 本地开发:利用 workspace 协议实现源码链接
  2. 调试技巧:使用现代工具进行跨包调试
  3. 代码规范:统一的工具链和规范
  4. 发布流程:标准化的发布流程和自动化

通过合理的工作流配置,可以实现:

  • ✅ 高效的开发体验
  • ✅ 快速的调试流程
  • ✅ 统一的代码质量
  • ✅ 自动化的发布流程

如果你对 Vue 3 企业级工程实践 感兴趣,可以查看我们的 架构实践分类 下的其他文章。

相关资源

相关文章