532 lines
11 KiB
Markdown
532 lines
11 KiB
Markdown
# MixVideo 开发指南
|
|
|
|
## 快速开始
|
|
|
|
### 环境准备
|
|
```bash
|
|
# 检查环境要求
|
|
node --version # >= 18.0.0
|
|
rustc --version # >= 1.70.0
|
|
pnpm --version # >= 8.0.0
|
|
|
|
# 克隆项目
|
|
git clone <repository-url>
|
|
cd mixvideo
|
|
|
|
# 安装依赖
|
|
pnpm install
|
|
|
|
# 启动开发环境
|
|
pnpm tauri:dev
|
|
```
|
|
|
|
### 项目结构概览
|
|
```
|
|
mixvideo/
|
|
├── .promptx/ # 开发规范文档
|
|
├── apps/desktop/ # 主应用
|
|
│ ├── src/ # React前端
|
|
│ └── src-tauri/ # Rust后端
|
|
├── docs/ # 项目文档
|
|
├── package.json # 根配置
|
|
├── pnpm-workspace.yaml # 工作空间配置
|
|
└── Cargo.toml # Rust工作空间
|
|
```
|
|
|
|
## 开发工作流
|
|
|
|
### 1. 功能开发流程
|
|
```bash
|
|
# 1. 创建功能分支
|
|
git checkout -b feature/新功能名称
|
|
|
|
# 2. 开发和测试
|
|
pnpm tauri:dev # 启动开发服务器
|
|
pnpm test # 运行测试
|
|
|
|
# 3. 代码检查
|
|
pnpm lint # ESLint检查
|
|
pnpm format # Prettier格式化
|
|
cargo clippy # Rust代码检查
|
|
|
|
# 4. 提交代码
|
|
git add .
|
|
git commit -m "feat: 添加新功能描述"
|
|
|
|
# 5. 推送和合并
|
|
git push origin feature/新功能名称
|
|
# 创建Pull Request
|
|
```
|
|
|
|
### 2. 提交信息规范
|
|
```bash
|
|
# 提交类型
|
|
feat: 新功能
|
|
fix: 修复bug
|
|
docs: 文档更新
|
|
style: 代码格式调整
|
|
refactor: 重构代码
|
|
test: 测试相关
|
|
chore: 构建工具或辅助工具的变动
|
|
|
|
# 示例
|
|
git commit -m "feat: 添加AI视频分类功能"
|
|
git commit -m "fix: 修复素材导入时的路径问题"
|
|
git commit -m "docs: 更新API文档"
|
|
```
|
|
|
|
### 3. 代码审查清单
|
|
- [ ] 功能是否按需求实现
|
|
- [ ] 代码是否遵循项目规范
|
|
- [ ] 是否有适当的错误处理
|
|
- [ ] 是否有相应的测试覆盖
|
|
- [ ] 性能是否有考虑
|
|
- [ ] 安全性是否有保障
|
|
- [ ] 文档是否更新
|
|
|
|
## 核心开发模式
|
|
|
|
### 前端开发模式
|
|
|
|
#### 1. 组件开发
|
|
```typescript
|
|
// 1. 定义类型
|
|
interface ComponentProps {
|
|
id: string;
|
|
title: string;
|
|
onAction?: (data: any) => void;
|
|
}
|
|
|
|
// 2. 实现组件
|
|
export const Component: FC<ComponentProps> = ({ id, title, onAction }) => {
|
|
// Hooks
|
|
const [state, setState] = useState();
|
|
const { data, loading } = useCustomHook();
|
|
|
|
// 事件处理
|
|
const handleAction = useCallback(() => {
|
|
onAction?.(data);
|
|
}, [onAction, data]);
|
|
|
|
// 渲染
|
|
return (
|
|
<div className="component-container">
|
|
{/* 组件内容 */}
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
#### 2. 状态管理
|
|
```typescript
|
|
// 使用Zustand进行状态管理
|
|
export const useFeatureStore = create<FeatureState>((set, get) => ({
|
|
// 状态
|
|
data: [],
|
|
loading: false,
|
|
error: null,
|
|
|
|
// 操作
|
|
fetchData: async () => {
|
|
set({ loading: true });
|
|
try {
|
|
const data = await api.getData();
|
|
set({ data, loading: false });
|
|
} catch (error) {
|
|
set({ error: error.message, loading: false });
|
|
}
|
|
},
|
|
}));
|
|
```
|
|
|
|
#### 3. 服务层调用
|
|
```typescript
|
|
// 调用Tauri命令
|
|
export class FeatureService {
|
|
static async getData(): Promise<Data[]> {
|
|
try {
|
|
return await invoke<Data[]>('get_data');
|
|
} catch (error) {
|
|
throw new Error(`获取数据失败: ${error}`);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 后端开发模式
|
|
|
|
#### 1. 数据模型
|
|
```rust
|
|
// 定义数据模型
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Entity {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub created_at: DateTime<Utc>,
|
|
pub updated_at: DateTime<Utc>,
|
|
}
|
|
|
|
impl Entity {
|
|
pub fn new(name: String) -> Self {
|
|
let now = Utc::now();
|
|
Self {
|
|
id: uuid::Uuid::new_v4().to_string(),
|
|
name,
|
|
created_at: now,
|
|
updated_at: now,
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 2. 仓库层
|
|
```rust
|
|
// 数据访问层
|
|
pub struct EntityRepository {
|
|
database: Arc<Database>,
|
|
}
|
|
|
|
impl EntityRepository {
|
|
pub async fn create(&self, entity: &Entity) -> Result<()> {
|
|
let conn = self.database.get_connection().await?;
|
|
// 数据库操作
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_by_id(&self, id: &str) -> Result<Option<Entity>> {
|
|
let conn = self.database.get_read_connection().await?;
|
|
// 查询操作
|
|
Ok(None)
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3. 业务服务
|
|
```rust
|
|
// 业务逻辑层
|
|
pub struct EntityService;
|
|
|
|
impl EntityService {
|
|
pub async fn create_entity(
|
|
repository: &EntityRepository,
|
|
request: CreateEntityRequest,
|
|
) -> Result<Entity> {
|
|
// 业务验证
|
|
if request.name.trim().is_empty() {
|
|
return Err(anyhow!("名称不能为空"));
|
|
}
|
|
|
|
// 创建实体
|
|
let entity = Entity::new(request.name);
|
|
|
|
// 保存到数据库
|
|
repository.create(&entity).await?;
|
|
|
|
Ok(entity)
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 4. Tauri命令
|
|
```rust
|
|
// 表现层命令
|
|
#[command]
|
|
pub async fn create_entity(
|
|
state: State<'_, AppState>,
|
|
request: CreateEntityRequest,
|
|
) -> Result<Entity, String> {
|
|
let repository = state.get_entity_repository()
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
EntityService::create_entity(&repository, request)
|
|
.await
|
|
.map_err(|e| e.to_string())
|
|
}
|
|
```
|
|
|
|
## 测试策略
|
|
|
|
### 前端测试
|
|
```typescript
|
|
// 组件测试
|
|
describe('Component', () => {
|
|
it('应该正确渲染', () => {
|
|
render(<Component id="1" title="Test" />);
|
|
expect(screen.getByText('Test')).toBeInTheDocument();
|
|
});
|
|
|
|
it('应该处理用户交互', async () => {
|
|
const onAction = vi.fn();
|
|
render(<Component id="1" title="Test" onAction={onAction} />);
|
|
|
|
fireEvent.click(screen.getByRole('button'));
|
|
await waitFor(() => {
|
|
expect(onAction).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
|
|
// Hook测试
|
|
describe('useCustomHook', () => {
|
|
it('应该返回正确的数据', async () => {
|
|
const { result } = renderHook(() => useCustomHook());
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.data).toBeDefined();
|
|
});
|
|
});
|
|
});
|
|
```
|
|
|
|
### 后端测试
|
|
```rust
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn test_create_entity() {
|
|
// 准备测试数据
|
|
let db = setup_test_database().await;
|
|
let repository = EntityRepository::new(db);
|
|
let request = CreateEntityRequest {
|
|
name: "Test Entity".to_string(),
|
|
};
|
|
|
|
// 执行测试
|
|
let result = EntityService::create_entity(&repository, request).await;
|
|
|
|
// 验证结果
|
|
assert!(result.is_ok());
|
|
let entity = result.unwrap();
|
|
assert_eq!(entity.name, "Test Entity");
|
|
}
|
|
}
|
|
```
|
|
|
|
## 调试技巧
|
|
|
|
### 前端调试
|
|
```typescript
|
|
// 1. 使用浏览器开发者工具
|
|
console.log('调试信息:', data);
|
|
console.error('错误信息:', error);
|
|
|
|
// 2. React DevTools
|
|
// 安装React DevTools浏览器扩展
|
|
|
|
// 3. Zustand DevTools
|
|
const useStore = create(
|
|
devtools((set, get) => ({
|
|
// store实现
|
|
}))
|
|
);
|
|
|
|
// 4. 网络请求调试
|
|
// 在Network面板查看Tauri命令调用
|
|
```
|
|
|
|
### 后端调试
|
|
```rust
|
|
// 1. 使用tracing进行日志记录
|
|
use tracing::{info, warn, error, debug};
|
|
|
|
#[instrument]
|
|
async fn debug_function() {
|
|
info!("函数开始执行");
|
|
debug!("调试信息: {:?}", data);
|
|
warn!("警告信息");
|
|
error!("错误信息: {}", error);
|
|
}
|
|
|
|
// 2. 使用dbg!宏
|
|
let result = dbg!(some_calculation());
|
|
|
|
// 3. 条件编译调试代码
|
|
#[cfg(debug_assertions)]
|
|
println!("调试模式下的输出");
|
|
```
|
|
|
|
### 数据库调试
|
|
```sql
|
|
-- 查看查询计划
|
|
EXPLAIN QUERY PLAN SELECT * FROM materials WHERE project_id = ?;
|
|
|
|
-- 检查索引使用
|
|
.schema materials
|
|
.indices materials
|
|
|
|
-- 分析表统计
|
|
ANALYZE;
|
|
```
|
|
|
|
## 性能优化
|
|
|
|
### 前端性能优化
|
|
```typescript
|
|
// 1. 组件优化
|
|
const OptimizedComponent = memo(({ data }) => {
|
|
const memoizedValue = useMemo(() => {
|
|
return expensiveCalculation(data);
|
|
}, [data]);
|
|
|
|
const memoizedCallback = useCallback(() => {
|
|
handleAction(data);
|
|
}, [data]);
|
|
|
|
return <div>{memoizedValue}</div>;
|
|
});
|
|
|
|
// 2. 懒加载
|
|
const LazyComponent = lazy(() => import('./LazyComponent'));
|
|
|
|
// 3. 虚拟化长列表
|
|
import { FixedSizeList as List } from 'react-window';
|
|
|
|
const VirtualList = ({ items }) => (
|
|
<List
|
|
height={600}
|
|
itemCount={items.length}
|
|
itemSize={80}
|
|
>
|
|
{({ index, style }) => (
|
|
<div style={style}>
|
|
<Item data={items[index]} />
|
|
</div>
|
|
)}
|
|
</List>
|
|
);
|
|
```
|
|
|
|
### 后端性能优化
|
|
```rust
|
|
// 1. 数据库连接池
|
|
let pool = ConnectionPool::new(database_url, pool_config)?;
|
|
|
|
// 2. 批量操作
|
|
async fn batch_insert(items: &[Item]) -> Result<()> {
|
|
let conn = pool.get().await?;
|
|
let tx = conn.transaction()?;
|
|
|
|
for item in items {
|
|
tx.execute("INSERT INTO ...", params![...])?;
|
|
}
|
|
|
|
tx.commit()?;
|
|
Ok(())
|
|
}
|
|
|
|
// 3. 异步并发
|
|
use futures::future::join_all;
|
|
|
|
let futures: Vec<_> = items.iter()
|
|
.map(|item| process_item(item))
|
|
.collect();
|
|
|
|
let results = join_all(futures).await;
|
|
```
|
|
|
|
## 常见问题解决
|
|
|
|
### 1. 构建问题
|
|
```bash
|
|
# 清理缓存
|
|
pnpm clean
|
|
rm -rf node_modules
|
|
rm -rf target
|
|
pnpm install
|
|
|
|
# Rust编译问题
|
|
cargo clean
|
|
cargo build
|
|
```
|
|
|
|
### 2. 开发环境问题
|
|
```bash
|
|
# 端口冲突
|
|
lsof -ti:1420 | xargs kill -9
|
|
|
|
# 权限问题
|
|
sudo chown -R $(whoami) ~/.cargo
|
|
```
|
|
|
|
### 3. 数据库问题
|
|
```rust
|
|
// 数据库锁定
|
|
// 检查是否有其他进程占用数据库
|
|
// 使用WAL模式减少锁定
|
|
|
|
// 迁移失败
|
|
// 检查SQL语法
|
|
// 验证外键约束
|
|
```
|
|
|
|
### 4. 前端问题
|
|
```typescript
|
|
// 状态更新问题
|
|
// 检查依赖数组
|
|
// 使用useCallback和useMemo
|
|
|
|
// 渲染性能问题
|
|
// 使用React DevTools Profiler
|
|
// 检查不必要的重渲染
|
|
```
|
|
|
|
## 部署指南
|
|
|
|
### 开发环境部署
|
|
```bash
|
|
# 启动开发服务器
|
|
pnpm tauri:dev
|
|
```
|
|
|
|
### 生产环境构建
|
|
```bash
|
|
# 构建应用
|
|
pnpm tauri:build
|
|
|
|
# 构建产物位置
|
|
# Windows: target/release/bundle/msi/
|
|
# macOS: target/release/bundle/dmg/
|
|
# Linux: target/release/bundle/deb/
|
|
```
|
|
|
|
### 发布流程
|
|
```bash
|
|
# 1. 更新版本号
|
|
# 修改 package.json 和 Cargo.toml 中的版本号
|
|
|
|
# 2. 创建发布标签
|
|
git tag v0.2.1
|
|
git push origin v0.2.1
|
|
|
|
# 3. GitHub Actions自动构建和发布
|
|
# 查看 .github/workflows/ 中的配置
|
|
```
|
|
|
|
## 最佳实践总结
|
|
|
|
### 代码质量
|
|
1. **遵循规范**: 严格按照项目编码规范开发
|
|
2. **测试驱动**: 为核心功能编写测试
|
|
3. **代码审查**: 所有代码都要经过审查
|
|
4. **文档更新**: 及时更新相关文档
|
|
|
|
### 性能考虑
|
|
1. **数据库优化**: 合理使用索引和查询优化
|
|
2. **前端优化**: 使用虚拟化、懒加载等技术
|
|
3. **内存管理**: 避免内存泄漏和过度使用
|
|
4. **网络优化**: 减少不必要的网络请求
|
|
|
|
### 安全意识
|
|
1. **输入验证**: 严格验证所有用户输入
|
|
2. **错误处理**: 不泄露敏感信息
|
|
3. **权限控制**: 实施适当的访问控制
|
|
4. **数据保护**: 保护用户数据安全
|
|
|
|
### 用户体验
|
|
1. **响应式设计**: 支持多种设备和屏幕尺寸
|
|
2. **加载状态**: 提供清晰的加载反馈
|
|
3. **错误提示**: 友好的错误信息和恢复建议
|
|
4. **无障碍性**: 支持键盘导航和屏幕阅读器
|