开发与生产工作流
本指南涵盖了 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 dev | dev 目录 | 主设计器开发 | 9527 |
npm run dev:uni | dev 目录 | UniApp 平台开发 | 9527 |
npm run pro:dev | platforms/pro | 生产平台 IDE | 9527 |
npm run pro-uni:dev | platforms/pro-uni | UniApp 生产平台 | 9527 |
npm run app:dev | apps/app | Web 应用示例 | 9527 |
npm run h5:dev | apps/h5 | H5 移动端应用 | 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:dev | dev | 开发构建 | 功能测试 |
npm run build:sit | sit | 集成构建 | QA 测试 |
npm run build:uat | uat | UAT 构建 | 干系人测试 |
npm run build:pre | pre | 预生产 | 最终预演 |
npm run build:prod | live | 生产构建 | 正式上线 |
构建脚本模式遵循: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 patch | 0.0.x | 仅错误修复 |
npm run minor | 0.x.0 | 新功能(向后兼容) |
npm run prerelease | 0.0.0-x | 预发布版本 |
每个发布命令都会触发完整的流水线:
- Lerna 版本升级(创建 git 标签)
- 跨所有包的完整构建
- 提交带有发布信息的 git commit
- 发布到 npm 注册表
- 同步到镜像注册表
发布过程
发布阶段使用 pnpm 的工作区感知发布功能:
pnpm -r publish --access public --publish-branch next --report-summary --no-git-checks
关键发布特性:
- 工作区感知:仅发布已更改的包
- 公开访问:包公开可用
- 分支定向:发布到
nextdist-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 别名路径与项目结构匹配 |
性能优化
为了在开发期间加快构建:
- 必要时使用
--force标志绕过 Vite 缓存 - 启用
watchModules以从文件监视中排除 node_modules - 针对现代浏览器目标禁用旧版本构建
- 使用选择性包构建:
npm run core:build而不是完整的 monorepo 构建
依赖冲突
遇到版本冲突时:
- 运行
npm run clean移除所有产物 - 运行
npm run reset进行完整的工作区重置 - 运行
npm run update将所有依赖项更新到最新的兼容版本
后续步骤
要深入了解 VTJ 的架构以及如何扩展系统:
- 构建配置和 Vite 集成 - 学习高级构建定制和 Vite 插件开发
- Create VTJ CLI 参考 - 掌握 CLI 工具和模板系统
- 架构概述 - 了解整体系统设计和组件交互
对于实际实现指导:
- 项目模板 - 开始使用特定的应用类型
- 自定义构建插件 - 使用自定义 Vite 插件扩展构建系统
VTJ 中的开发工作流旨在提供从本地开发到生产部署的无缝体验,并为跨多个平台和环境的测试、构建和发布提供强大的工具支持。
参考资料
- 官方文档:vtj.pro/
- 在线平台:app.vtj.pro/
- 开源仓库:gitee.com/newgateway/…