11 KiB
11 KiB
MixVideo 开发指南
快速开始
环境准备
# 检查环境要求
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. 功能开发流程
# 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. 提交信息规范
# 提交类型
feat: 新功能
fix: 修复bug
docs: 文档更新
style: 代码格式调整
refactor: 重构代码
test: 测试相关
chore: 构建工具或辅助工具的变动
# 示例
git commit -m "feat: 添加AI视频分类功能"
git commit -m "fix: 修复素材导入时的路径问题"
git commit -m "docs: 更新API文档"
3. 代码审查清单
- 功能是否按需求实现
- 代码是否遵循项目规范
- 是否有适当的错误处理
- 是否有相应的测试覆盖
- 性能是否有考虑
- 安全性是否有保障
- 文档是否更新
核心开发模式
前端开发模式
1. 组件开发
// 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. 状态管理
// 使用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. 服务层调用
// 调用Tauri命令
export class FeatureService {
static async getData(): Promise<Data[]> {
try {
return await invoke<Data[]>('get_data');
} catch (error) {
throw new Error(`获取数据失败: ${error}`);
}
}
}
后端开发模式
1. 数据模型
// 定义数据模型
#[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. 仓库层
// 数据访问层
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. 业务服务
// 业务逻辑层
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命令
// 表现层命令
#[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())
}
测试策略
前端测试
// 组件测试
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();
});
});
});
后端测试
#[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");
}
}
调试技巧
前端调试
// 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命令调用
后端调试
// 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!("调试模式下的输出");
数据库调试
-- 查看查询计划
EXPLAIN QUERY PLAN SELECT * FROM materials WHERE project_id = ?;
-- 检查索引使用
.schema materials
.indices materials
-- 分析表统计
ANALYZE;
性能优化
前端性能优化
// 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>
);
后端性能优化
// 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. 构建问题
# 清理缓存
pnpm clean
rm -rf node_modules
rm -rf target
pnpm install
# Rust编译问题
cargo clean
cargo build
2. 开发环境问题
# 端口冲突
lsof -ti:1420 | xargs kill -9
# 权限问题
sudo chown -R $(whoami) ~/.cargo
3. 数据库问题
// 数据库锁定
// 检查是否有其他进程占用数据库
// 使用WAL模式减少锁定
// 迁移失败
// 检查SQL语法
// 验证外键约束
4. 前端问题
// 状态更新问题
// 检查依赖数组
// 使用useCallback和useMemo
// 渲染性能问题
// 使用React DevTools Profiler
// 检查不必要的重渲染
部署指南
开发环境部署
# 启动开发服务器
pnpm tauri:dev
生产环境构建
# 构建应用
pnpm tauri:build
# 构建产物位置
# Windows: target/release/bundle/msi/
# macOS: target/release/bundle/dmg/
# Linux: target/release/bundle/deb/
发布流程
# 1. 更新版本号
# 修改 package.json 和 Cargo.toml 中的版本号
# 2. 创建发布标签
git tag v0.2.1
git push origin v0.2.1
# 3. GitHub Actions自动构建和发布
# 查看 .github/workflows/ 中的配置
最佳实践总结
代码质量
- 遵循规范: 严格按照项目编码规范开发
- 测试驱动: 为核心功能编写测试
- 代码审查: 所有代码都要经过审查
- 文档更新: 及时更新相关文档
性能考虑
- 数据库优化: 合理使用索引和查询优化
- 前端优化: 使用虚拟化、懒加载等技术
- 内存管理: 避免内存泄漏和过度使用
- 网络优化: 减少不必要的网络请求
安全意识
- 输入验证: 严格验证所有用户输入
- 错误处理: 不泄露敏感信息
- 权限控制: 实施适当的访问控制
- 数据保护: 保护用户数据安全
用户体验
- 响应式设计: 支持多种设备和屏幕尺寸
- 加载状态: 提供清晰的加载反馈
- 错误提示: 友好的错误信息和恢复建议
- 无障碍性: 支持键盘导航和屏幕阅读器