17 KiB
17 KiB
Uni-App-X 工程化最佳实践
📚 概述
本文档介绍了 mall 项目的工程化实践,包括项目结构、开发流程、构建配置、代码规范等内容,参考 CRMEB 的工程化标准。
1. 项目结构
1.1 推荐目录结构
mall/
├── ai/ # AI 相关配置
├── components/
│ ├── analytics/ # 分析组件
│ ├── basic/ # ✨ 基础组件 (新增)
│ │ ├── Button.uvue
│ │ ├── Input.uvue
│ │ ├── Select.uvue
│ │ ├── Checkbox.uvue
│ │ ├── Radio.uvue
│ │ ├── Toggle.uvue
│ │ └── DatePicker.uvue
│ ├── container/ # ✨ 容器组件 (新增)
│ │ ├── Card.uvue
│ │ ├── Modal.uvue
│ │ ├── Drawer.uvue
│ │ ├── Collapse.uvue
│ │ ├── Tabs.uvue
│ │ └── Pagination.uvue
│ ├── data/ # ✨ 数据展示组件 (新增)
│ │ ├── Table.uvue
│ │ ├── List.uvue
│ │ ├── Tree.uvue
│ │ ├── Tag.uvue
│ │ ├── Badge.uvue
│ │ └── Avatar.uvue
│ ├── form/ # ✨ 表单组件 (新增)
│ │ ├── Form.uvue
│ │ ├── FormItem.uvue
│ │ ├── FormGroup.uvue
│ │ ├── Upload.uvue
│ │ └── RichEditor.uvue
│ ├── feedback/ # ✨ 反馈组件 (新增)
│ │ ├── Message.uvue
│ │ ├── Alert.uvue
│ │ ├── Tooltip.uvue
│ │ ├── Loading.uvue
│ │ ├── Empty.uvue
│ │ └── Error.uvue
│ ├── navigation/ # ✨ 导航组件 (新增)
│ │ ├── Breadcrumb.uvue
│ │ ├── Menu.uvue
│ │ ├── Navbar.uvue
│ │ └── Sidebar.uvue
│ ├── supadb/ # 数据库组件
│ └── ...
├── docs/
│ ├── STYLE_SPECIFICATION.md # ✨ 样式规范
│ ├── PAGE_STRUCTURE_SPECIFICATION.md # ✨ 页面结构规范
│ ├── COMPONENT_SPECIFICATION.md # ✨ 组件规范
│ ├── IMPLEMENTATION_ROADMAP.md # ✨ 实现路线图
│ ├── ENGINEERING_BEST_PRACTICES.md # ✨ 工程化最佳实践
│ └── ...
├── layouts/
│ ├── admin/
│ │ ├── AdminLayout.uvue # 增强版
│ │ └── utils/
│ │ ├── menu.uts
│ │ ├── nav.uts
│ │ └── state.uts
│ └── ...
├── pages/
│ ├── templates/ # ✨ 页面模板 (新增)
│ │ ├── ListPage.uvue
│ │ ├── FormPage.uvue
│ │ └── DetailPage.uvue
│ ├── mall/
│ │ ├── admin/
│ │ │ ├── maintain/
│ │ │ │ └── system-info.uvue
│ │ │ └── ...
│ │ └── ...
│ └── ...
├── styles/ # ✨ 全局样式 (优化)
│ ├── common.scss # 通用样式
│ ├── utilities.scss # 工具类
│ └── variables.scss # 变量(引用 uni.scss)
├── uni_modules/
│ ├── ak-req/
│ ├── charts/
│ └── ...
├── utils/
│ ├── request.uts # 网络请求
│ ├── store.uts # 状态管理
│ ├── validators.uts # ✨ 验证器工具
│ ├── format.uts # ✨ 格式化工具
│ └── ...
├── uni.scss # ✨ 设计变量系统 (已更新)
├── App.uvue
├── main.js
├── main.uts
├── manifest.json
├── package.json
├── tsconfig.json
├── pages.json
├── platformConfig.json
└── README.md
1.2 新增目录说明
| 目录 | 用途 | 说明 |
|---|---|---|
components/basic/ |
基础组件 | Button, Input, Select 等 |
components/container/ |
容器组件 | Card, Modal, Pagination 等 |
components/data/ |
数据展示 | Table, List, Tree 等 |
components/form/ |
表单组件 | Form, FormItem, Upload 等 |
components/feedback/ |
反馈组件 | Message, Alert, Loading 等 |
components/navigation/ |
导航组件 | Breadcrumb, Menu, Navbar 等 |
pages/templates/ |
页面模板 | ListPage, FormPage, DetailPage |
styles/ |
全局样式 | 共享样式和工具类 |
2. 开发规范
2.1 文件命名规范
| 类型 | 规范 | 示例 |
|---|---|---|
| 组件文件 | PascalCase | Button.uvue, FormItem.uvue |
| 业务页面 | kebab-case | system-info.uvue |
| 工具脚本 | camelCase + .uts | validators.uts, formatters.uts |
| 样式文件 | kebab-case + .scss | common.scss, utilities.scss |
| 配置文件 | camelCase + .uts | config.uts |
| 常量文件 | UPPER_SNAKE_CASE | CONSTANTS.uts |
2.2 导入规范
// ✅ 正确用法
// 1. 组件导入
import Button from '@/components/basic/Button.uvue'
import Card from '@/components/container/Card.uvue'
import Table from '@/components/data/Table.uvue'
// 2. 工具导入
import { validateEmail, validatePhone } from '@/utils/validators.uts'
import { formatDate, formatTime } from '@/utils/format.uts'
// 3. 类型导入 (UTS)
import type { MenuConfig } from '@/types/mall-types.uts'
// 4. 样式导入
import '@/styles/common.scss'
// ❌ 错误用法
// 不要使用相对路径
import Button from '../../../components/basic/Button.uvue' // ❌
// 不要混乱地导入
import * from '@/components/basic/Button.uvue' // ❌
// 不要导入 node_modules 中的代码(除非必要)
import { ref } from 'vue' // 这是可以的,但应该在文件顶部
2.3 TypeScript 规范
虽然使用 UTS(Uni-App TypeScript),但也遵循 TypeScript 最佳实践:
// ✅ 正确用法
// 1. 定义类型接口
interface ButtonProps {
type?: "primary" | "default" | "danger";
size?: "sm" | "md" | "lg";
label: string;
disabled?: boolean;
loading?: boolean;
}
// 2. 使用类型标注
const props = withDefaults(defineProps<ButtonProps>(), {
type: "primary",
size: "md",
disabled: false,
loading: false,
});
// 3. 定义事件类型
const emit = defineEmits<{
click: [];
change: [value: string];
submit: [formData: Record<string, any>];
}>();
// 4. 使用类型断言(谨慎)
const element = event.target as HTMLInputElement;
// ❌ 错误用法
// 不要使用 any 类型
const data: any = {
// ❌
name: "test",
};
// 不要忽略类型检查
const props = defineProps({
// ❌ 无类型定义
label: String,
});
// 不要过度使用 as
const value = data as unknown as string as number; // ❌
2.4 代码注释规范
// ✅ 正确用法
/**
* Button 组件
* 支持多种类型、尺寸和状态
*
* @example
* <Button type="primary" label="创建" @click="handleCreate" />
*/
export default {
name: "Button",
// ...
};
// 方法注释
/**
* 处理按钮点击事件
* @param event - 点击事件
* @returns 无返回值
*/
const handleClick = (event: Event) => {
// ...
};
// 复杂逻辑注释
if (loading.value) {
// 加载中时显示加载指示器
return showLoadingIndicator();
}
// ❌ 错误用法
// 不要写无用的注释
const name = ref(""); // 设置 name ❌
// 不要注释掉代码
// const oldWay = () => { ... } ❌
// 不要写过时的注释
// TODO: 这个任务已经完成了 ❌
3. Git 工作流
3.1 分支策略
采用 Git Flow 分支模式:
main (生产分支)
↑
release/v1.0.0 (发布分支)
↑
develop (开发分支)
↑
feature/component-button (功能分支)
feature/page-list (功能分支)
bugfix/sidebar-display (缺陷分支)
3.2 分支命名规范
| 分支类型 | 命名规范 | 示例 |
|---|---|---|
| 功能分支 | feature/<feature-name> |
feature/component-button |
| 缺陷分支 | bugfix/<bug-name> |
bugfix/sidebar-display |
| 热修复 | hotfix/<issue> |
hotfix/security-issue |
| 发布分支 | release/v<version> |
release/v1.0.0 |
3.3 提交消息规范
遵循 Conventional Commits 规范:
<type>(<scope>): <subject>
<body>
<footer>
类型 (type)
| 类型 | 说明 |
|---|---|
| feat | 新功能 |
| fix | 缺陷修复 |
| docs | 文档更新 |
| style | 代码格式(不影响功能) |
| refactor | 代码重构 |
| perf | 性能优化 |
| test | 添加测试 |
| chore | 构建/依赖/工具 |
示例
feat(components): add Button component with 4 types and 3 sizes
- Support primary, default, danger, success types
- Support sm, md, lg sizes
- Support disabled and loading states
- Add unit tests and documentation
Closes #123, #124
3.4 代码审查清单
推送 PR 前检查:
- 代码遵循样式规范
- 所有变量使用 uni.scss 设计变量
- 添加了必要的注释
- 编写了单元测试
- 文档已更新
- 无 console.log 和调试代码
- 无未使用的导入
- 类型检查无错误
4. 构建和打包
4.1 打包命令
# 开发模式
npm run dev
# 生产打包
npm run build
# 预览生产构建
npm run preview
# 类型检查
npm run type-check
# 代码格式化
npm run format
# 代码检查
npm run lint
4.2 环境配置
在 .env 文件中配置:
# .env.development
VITE_API_BASE_URL=http://localhost:3000
VITE_APP_ENV=development
# .env.production
VITE_API_BASE_URL=https://api.example.com
VITE_APP_ENV=production
4.3 构建优化
代码分割
// 路由懒加载
const routes = [
{
path: "/admin/system-info",
component: () => import("@/pages/mall/admin/maintain/system-info.uvue"),
},
];
资源优化
// 图片优化
const image = 'image.webp' // 使用现代格式
// CSS 优化
// 在 uni.scss 中定义所有常用颜色和尺寸变量
$primary-color: #1890ff
$space-md: 16px
5. 测试规范
5.1 单元测试
// Button.test.ts
import { describe, it, expect, vi } from "vitest";
import { mount } from "@vue/test-utils";
import Button from "@/components/basic/Button.uvue";
describe("Button Component", () => {
it("renders button with label", () => {
const wrapper = mount(Button, {
props: { label: "Click me" },
});
expect(wrapper.text()).toBe("Click me");
});
it("emits click event when clicked", async () => {
const wrapper = mount(Button, {
props: { label: "Click" },
});
await wrapper.find("button").trigger("click");
expect(wrapper.emitted("click")).toBeTruthy();
});
it("disables button when disabled prop is true", () => {
const wrapper = mount(Button, {
props: { label: "Click", disabled: true },
});
expect(wrapper.find("button").attributes("disabled")).toBeDefined();
});
it("applies correct class based on type prop", () => {
const wrapper = mount(Button, {
props: { label: "Click", type: "danger" },
});
expect(wrapper.find("button").classes()).toContain("btn-danger");
});
});
5.2 测试覆盖率目标
| 类型 | 目标 |
|---|---|
| 语句覆盖 | ≥ 80% |
| 分支覆盖 | ≥ 75% |
| 函数覆盖 | ≥ 80% |
| 行覆盖 | ≥ 80% |
5.3 测试运行命令
# 运行所有测试
npm run test
# 运行特定文件的测试
npm run test Button
# 生成覆盖率报告
npm run test:coverage
# 监视模式
npm run test:watch
6. 性能优化
6.1 加载性能目标
| 指标 | 目标 | 当前 |
|---|---|---|
| FCP (首次内容绘制) | < 1.5s | TBD |
| LCP (最大内容绘制) | < 2.5s | TBD |
| CLS (累积布局偏移) | < 0.1 | TBD |
| TTI (可交互时间) | < 3s | TBD |
6.2 优化技巧
// 1. 虚拟滚动(大列表)
<virtual-scroller :items="largeList" :item-height="50">
<template #default="{ item }">
<div>{{ item }}</div>
</template>
</virtual-scroller>
// 2. 图片懒加载
<img v-lazy="imageUrl" />
// 3. 路由懒加载
const routes = [
{
path: '/admin',
component: () => import('@/layouts/admin/AdminLayout.uvue'),
},
]
// 4. 代码分割
const Table = defineAsyncComponent(() =>
import('@/components/data/Table.uvue')
)
// 5. 防抖和节流
import { debounce, throttle } from 'lodash-es'
const handleSearch = debounce(() => {
// 搜索逻辑
}, 300)
7. 监测和日志
7.1 日志记录
// 使用结构化日志
import { logger } from "@/utils/logger.uts";
// 不同级别
logger.debug("调试信息"); // 开发使用
logger.info("信息"); // 正常操作
logger.warn("警告"); // 可能的问题
logger.error("错误"); // 出现问题
7.2 错误跟踪
// 全局错误处理
app.config.errorHandler = (err, instance, info) => {
logger.error("应用错误:", err);
// 发送到错误追踪服务
trackError(err);
};
// 未捕获的 Promise 拒绝
window.addEventListener("unhandledrejection", (event) => {
logger.error("未处理的 Promise 拒绝:", event.reason);
});
7.3 性能监测
// 性能标记
performance.mark("page-load-start");
// ... 页面加载逻辑 ...
performance.mark("page-load-end");
performance.measure("page-load", "page-load-start", "page-load-end");
const measure = performance.getEntriesByName("page-load")[0];
logger.info(`页面加载时间: ${measure.duration}ms`);
8. 依赖管理
8.1 package.json 脚本
{
"scripts": {
"dev": "uni dev:h5",
"build": "uni build:h5",
"preview": "vite preview",
"type-check": "tsc --noEmit",
"format": "prettier --write .",
"lint": "eslint . --ext .vue,.ts,.uts",
"test": "vitest",
"test:coverage": "vitest --coverage"
}
}
8.2 依赖最小化
- 避免重复的依赖
- 定期更新依赖
- 移除未使用的依赖
- 选择轻量级替代品
# 检查未使用的依赖
npm ls --depth=0
# 检查过时的依赖
npm outdated
9. 文档维护
9.1 文档位置
所有文档都放在 docs/ 目录:
docs/
├── STYLE_SPECIFICATION.md
├── PAGE_STRUCTURE_SPECIFICATION.md
├── COMPONENT_SPECIFICATION.md
├── IMPLEMENTATION_ROADMAP.md
├── ENGINEERING_BEST_PRACTICES.md
└── README.md
9.2 文档更新频率
| 文档 | 更新频率 | 维护者 |
|---|---|---|
| 样式规范 | 半年 | 设计团队 |
| 页面结构规范 | 每月 | 前端团队 |
| 组件规范 | 每月 | 前端团队 |
| 实现路线图 | 每周 | 项目经理 |
| 工程化最佳实践 | 按需 | 技术负责人 |
9.3 README 模板
每个模块都应有 README.md:
# Module Name
## 描述
简明扼要的模块描述
## 结构
module/ ├── Component.uvue ├── types.uts └── utils.uts
## 使用方法
代码示例
## 贡献指南
如何贡献
## 许可证
MIT
10. 发布流程
10.1 版本管理
使用语义化版本 (Semantic Versioning):
MAJOR.MINOR.PATCH
v1.2.3
- MAJOR: 不兼容的改动
- MINOR: 新增功能(向后兼容)
- PATCH: 缺陷修复
10.2 发布检查清单
在发布新版本前:
- 所有测试通过
- 文档更新
- CHANGELOG 更新
- 版本号更新 (package.json)
- Git 标签创建
- 构建成功
- 性能检测通过
- 安全审计通过
10.3 CHANGELOG 格式
# Changelog
## [1.2.0] - 2026-02-28
### Added
- 新增 Button 组件
- 新增 Input 组件
- 新增表单验证器
### Changed
- 更新设计变量系统
- 改进性能(40% 更快)
### Fixed
- 修复 Modal 动画闪烁问题
- 修复移动端布局问题
### Deprecated
- 弃用旧的 Button 样式
### Security
- 修复 XSS 漏洞
📝 总结
✅ 工程化核心原则:
- 代码一致性 - 遵循命名和格式规范
- 自动化 - 使用脚本和工具自动化重复任务
- 可维护性 - 清晰的代码和充分的文档
- 可测试性 - 编写可测试的代码
- 性能 - 不断监测和优化
❌ 禁止做法:
- 不要不遵循 Git 工作流
- 不要提交到 main 分支(使用 PR)
- 不要忽视代码审查
- 不要发布前没有测试
- 不要创建无文档的代码
文档版本: 1.0
最后更新: 2026-01-31
维护者: AI Assistant