AI 驱动的 Vue3 应用开发平台 深入探究(二十二):CLI与工具链之开发与生产工作流

0 阅读5分钟

开发与生产工作流

本指南涵盖了 VTJ 的完整开发生命周期,从本地开发到生产部署。VTJ 采用了精密的 Monorepo 架构,结合 pnpm workspaces、Vite 构建系统以及自动化发布流水线,支持多种部署目标和平台。

工作流架构

VTJ 实施了一种分层开发方法,将包开发与应用部署分离开来。该架构通过统一的 CLI 系统,同时支持库包和生产应用。

graph TD
    subgraph Release
        H[版本升级] --> I[Lerna构建]
        I --> J[包发布]
        J --> K[镜像同步]
    end
    subgraph Development
        A[本地开发] --> B[测试]
        B --> C[构建包]
        C --> D[本地预览]
    end
    subgraph Production
        E[环境构建] --> F[多平台输出]
        F --> G[部署]
    end
    C --> E
    D -.-> E

该工作流集成了三个不同的阶段:具备热重载功能的活跃开发、跨多环境的生产构建,以及自动发布到 npm 注册表。

本地开发工作流

VTJ 的本地开发采用基于目标的方法,开发者可以专注于特定的包、平台或演示应用。

启动开发服务器

根目录的 package.json 提供了针对不同开发场景的便捷脚本:

命令目标用途端口
npm run devdev 目录主设计器开发9527
npm run dev:unidev 目录UniApp 平台开发9527
npm run pro:devplatforms/pro生产平台 IDE9527
npm run pro-uni:devplatforms/pro-uniUniApp 生产平台9527
npm run app:devapps/appWeb 应用示例9527
npm run h5:devapps/h5H5 移动端应用9527

开发服务器默认使用启用了热模块替换(HMR)的 Vite。CLI 的 createServer 函数配置了 CORS、端口绑定(默认为 9527)以及用于 API 模拟的可选代理配置。

💡 默认开发端口(9527)定义在 CLI 的 defaults.ts 配置中。你可以通过特定环境的代理配置覆盖它,或者向 createViteConfig 传递自定义端口设置。

开发环境配置

VTJ 通过 JSON 文件使用基于环境的配置:

env.json (默认配置)
├── env.local.json (本地开发)
├── env.dev.json (开发环境)
├── env.sit.json (系统集成测试)
├── env.uat.json (用户验收测试)
├── env.pre.json (预生产)
└── env.live.json (生产环境)

CLI 的 getConfig 函数将基础配置与特定环境的覆盖配置合并:

export function getConfig(envPath: string, type: string): Record<string, any> {
  const defaults = resolve(envPath, "env.json");
  const env = resolve(envPath, `env.${type}.json`);
  const defaultConfig = pathExistsSync(defaults) ? readJsonSync(defaults) : {};
  const envConfig = pathExistsSync(env) ? readJsonSync(env) : {};
  return Object.assign({}, defaultConfig, envConfig);
}

这种模式允许在不同环境之间无缝切换,无需更改代码——只需在构建期间切换 ENV_TYPE 环境变量。

测试工作流

测试通过 Vitest 集成到每个包中,并支持 DOM 测试的 jsdom 环境。

运行测试

VTJ 为每个包提供了细粒度的测试命令:

npm run core:test
npm run cli:test
npm run renderer:test

# 运行整个 monorepo 的所有测试
npm run test

每个包包含一个 vitest.config.ts 配置文件,用于设置 jsdom 作为测试环境:

import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    environment: "jsdom",
  },
});

Nx 依赖管理

Monorepo 使用 Nx 来编排具有依赖感知的测试执行。nx.json 配置确保测试按拓扑顺序运行:

{
  "targetDefaults": {
    "test": {
      "dependsOn": ["^test"]
    }
  }
}

这意味着当测试 @vtj/renderer 时,Nx 会自动先测试依赖包(如 @vtj/core),从而确保隔离于依赖缺陷。

构建过程

VTJ 的构建系统区分了库包(通过 npm 分发)和应用(部署到服务器)。

库包构建

库包使用 @vtj/cli 的标准化构建配置。每个库的 vite.config.ts 委托给 createViteConfig,并传入特定库的选项:

import { createViteConfig } from "@vtj/cli";

export default createViteConfig({
  lib: true,
  dts: true,
  version: true,
  formats: ["es", "cjs"],
  external: ["@vtj/base"],
});

构建过程生成:

  • ES 模块(.mjs),用于现代打包工具
  • CommonJS(.cjs),用于 Node.js 兼容性
  • TypeScript 声明(types/ 目录)

构建配置自动处理:

  • 通过 vue-tsc 进行 TypeScript 编译
  • 带有代码分割的 Rollup 打包
  • CSS 提取到独立文件
  • 外部依赖排除

应用构建

应用构建支持多环境目标,并进行特定于环境的编译:

命令环境输出用例
npm run build:devdev开发构建功能测试
npm run build:sitsit集成构建QA 测试
npm run build:uatuatUAT 构建干系人测试
npm run build:prepre预生产最终预演
npm run build:prodlive生产构建正式上线

构建脚本模式遵循:cross-env ENV_TYPE=<type> vite build,该命令在构建过程中加载对应的 env.<type>.json 配置。

构建输出结构

Vite 的构建配置使用智能代码分割,定义于 packages/cli/src/vite/build.ts

const defaultManualChunks = (id: string) => {
  if (id.includes("node_modules")) {
    const arr = id.split("node_modules/");
    const dirs = arr[arr.length - 1].split("/");
    const name = dirs[0];
    if (PACKAGES.includes(name)) {
      return name;
    }
    if (P_MAP[name]) {
      return P_MAP[name];
    }
    // ... 更多分块逻辑
  }
};

这会创建优化的打包文件,并将供应商块按以下分类分离:

  • 框架代码:Vue, VueRouter, VueDemi
  • UI 库:Element Plus, Vant
  • 工具库:Lodash, async-validator
  • 图表库:ECharts, ZRender

多平台部署

VTJ 支持从单一代码库部署到多个平台:Web(桌面/移动浏览器)、H5(移动 Web)和 UniApp(微信小程序、原生应用)。

graph TD
    A[源代码] --> B[构建过程]
    B --> C{平台目标}
    C --> D[Web构建]
    C --> E[H5构建]
    C --> F[UniApp构建]
    D --> G[静态资源]
    E --> G
    F --> H[UniApp包]
    G --> I[CDN/Web服务器]
    H --> J[小程序或应用商店]

特定平台构建命令

# Web 平台
npm run pro:build

# H5 移动端平台
npm run mui:build

# UniApp 平台(小程序)
npm run uniapp:mp

# 所有平台同时构建
npm run dev:build

UniApp 构建使用专门的 Vite 配置 createUniappViteConfig,其中包括 Node.js API 的 polyfills 和用于 uni-app 兼容性的特定别名配置。

发布与发布工作流

VTJ 使用 Lerna 进行自动化版本控制和发布,并结合 Conventional Commits 标准生成变更日志。

版本管理

发布过程遵循语义化版本控制,采用 Lerna 的独立版本模式 lerna.json

{
  "version": "independent",
  "useNx": true,
  "npmClient": "pnpm"
}

这允许每个包维护自己的版本号,当更改提交到该特定包时独立递增。

发布脚本

命令版本递增类型动作
npm run patch0.0.x仅错误修复
npm run minor0.x.0新功能(向后兼容)
npm run prerelease0.0.0-x预发布版本

每个发布命令都会触发完整的流水线:

  1. Lerna 版本升级(创建 git 标签)
  2. 跨所有包的完整构建
  3. 提交带有发布信息的 git commit
  4. 发布到 npm 注册表
  5. 同步到镜像注册表

发布过程

发布阶段使用 pnpm 的工作区感知发布功能:

pnpm -r publish --access public --publish-branch next --report-summary --no-git-checks

关键发布特性:

  • 工作区感知:仅发布已更改的包
  • 公开访问:包公开可用
  • 分支定向:发布到 next dist-tag 用于 Beta 版本
  • 提交验证:通过 commitlint 强制执行 Conventional Commit 格式

注册表同步

发布后,sync 脚本将包同步到 npm 镜像注册表,以便在某些区域更快访问:

const modules = [
  "create-vtj",
  "@vtj/cli",
  "@vtj/utils",
  // ... 20+ 包
];

async function sendSync(name) {
  const res = await axios.put(
    `https://registry-direct.npmmirror.com/${name}/sync?sync_upstream=true`,
  );
  // 轮询同步状态直到完成
}

这确保包在发布后立即可用于 npmmirror.com 等镜像。

Monorepo 管理

VTJ 使用 pnpm workspaces 结合 Nx,以实现高效的构建编排和依赖管理。

工作区结构

工作区配置定义了包的位置 pnpm-workspace.yaml

packages:
  - "packages/*" # 核心库包
  - "platforms/*" # 生产平台
  - "apps/*" # 示例应用
  - "create-vtj" # CLI 脚手架工具
  - "dev" # 开发环境
  - "docs" # 文档站点

依赖缓存

Nx 基于文件哈希和依赖图提供构建缓存 nx.json

{
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["{projectRoot}/dist", "{projectRoot}/types"]
    }
  }
}

这意味着:

  • 依赖项先构建(拓扑顺序)
  • 构建输出按输入哈希缓存
  • 未更改的包完全跳过重建

清理工作区

clean 脚本移除所有构建产物和锁文件,以便重新开始:

const DIRS = ["lib", "cdn", "types", "dist", "coverage", "temp"];
const FILES = ["tsconfig.tsbuildinfo", "package-lock.json", "pnpm-lock.yaml"];

// 清理包、平台、应用和特殊目录
await cleanDir(await getPackages(PACKAGES_PATH), PACKAGES_PATH);
await cleanDir(await getPackages(PLATFORMS_PATH), PLATFORMS_PATH);
await cleanDir(await getPackages(APPS_PATH), APPS_PATH);

reset 命令提供完整的工作区重置:pnpm run clean && pnpm run setup

💡 当遇到依赖冲突或 node_modules 损坏时,请使用 reset 命令。这在切换到包版本差异显著的分支后特别有用。

使用 Create VTJ 进行项目脚手架搭建

create-vtj CLI 工具为各种用例提供项目模板,自动化设置带有预配置构建管道的新 VTJ 项目。

可用模板

npm create vtj@latest

可用模板包括:

  • app:功能齐全的 Web 应用,集成设计器
  • h5:移动端优化的 H5 应用
  • uniapp:基于 UniApp 的小程序或应用
  • library:组件或工具库
  • material:自定义物料组件库
  • plugin:设计器插件开发
  • extension:浏览器扩展

每个模板包括:

  • 预配置的 Vite 构建设置
  • 环境配置文件
  • 用于 API 模拟的代理配置
  • TypeScript 配置
  • 包依赖项

CLI 构建过程

create-vtj CLI 本身使用 unbuild 进行分发:

export default defineBuildConfig({
  entries: ["src/index"],
  clean: true,
  declaration: true,
  rollup: {
    emitCJS: true,
    inlineDependencies: true,
  },
  outDir: "dist",
  stub: false,
});

这会生成带有内联依赖项的 ESM 和 CJS 格式,以便独立 CLI 执行。

故障排除

常见构建问题

问题原因解决方案
构建卡在依赖解析上工作区循环依赖检查 pnpm-workspace.yaml 并运行 pnpm install --force
构建后类型错误缺少 TypeScript 声明确保 Vite 配置中 dts: true 并重新构建
端口被占用 (9527)之前的开发服务器仍在运行终止进程或更改代理配置中的端口
导入解析错误别名配置不正确验证 Vite 别名路径与项目结构匹配

性能优化

为了在开发期间加快构建:

  1. 必要时使用 --force 标志绕过 Vite 缓存
  2. 启用 watchModules 以从文件监视中排除 node_modules
  3. 针对现代浏览器目标禁用旧版本构建
  4. 使用选择性包构建:npm run core:build 而不是完整的 monorepo 构建

依赖冲突

遇到版本冲突时:

  1. 运行 npm run clean 移除所有产物
  2. 运行 npm run reset 进行完整的工作区重置
  3. 运行 npm run update 将所有依赖项更新到最新的兼容版本

后续步骤

要深入了解 VTJ 的架构以及如何扩展系统:

  • 构建配置和 Vite 集成 - 学习高级构建定制和 Vite 插件开发
  • Create VTJ CLI 参考 - 掌握 CLI 工具和模板系统
  • 架构概述 - 了解整体系统设计和组件交互

对于实际实现指导:

  • 项目模板 - 开始使用特定的应用类型
  • 自定义构建插件 - 使用自定义 Vite 插件扩展构建系统

VTJ 中的开发工作流旨在提供从本地开发到生产部署的无缝体验,并为跨多个平台和环境的测试、构建和发布提供强大的工具支持。

参考资料