web/apps/mobile/docs/DEVELOPMENT.md
本文档定义 apps/mobile(Expo + React Native)的开发规范,与 monorepo 根目录的 .cursor/rules 及 AGENTS.md 互补;涉及 TypeScript、样式、状态、路由等均以本文为准。
app/ 目录)StyleSheet 仅当必要@km/shared-utils/universal、@km/shared-public(静态资源)apps/mobile/
├── app/ # 路由页面(Expo Router)
│ ├── _layout.tsx # 根布局
│ ├── index.tsx # 首页
│ └── *.tsx # 其他路由
├── store/ # Zustand stores
│ └── *.ts
├── components/ # 可复用 UI 组件(可选)
├── hooks/ # 自定义 hooks(可选)
├── constants/ # 常量、枚举(可选)
├── docs/ # 文档(本文档等)
├── global.css # NativeWind 入口
├── tailwind.config.js
├── metro.config.js
├── babel.config.js
├── app.json
├── package.json
└── tsconfig.json
app/ 下,通过文件命名生成路由。store/,按领域或功能拆分(如 todoStore.ts)。components/,按功能分子目录(如 components/Button/)。store/todoStore.ts 内导出 TodoItem),或集中放在 types/。app/todo.tsx、app/user-profile.tsx;目录用 _layout.tsx 表示布局。export default function TodoScreen()。*Store.ts,如 todoStore.ts;hook 以 use 开头,如 useTodoStore。use*.ts,如 useDebounce.ts。const 对象 + as const,避免 enum。is / has / should,如 isLoading、hasError。type 定义对象形状;必要时再用 interface。any;用 unknown 或具体类型,必要时再断言。type 定义。.cursor/rules/typescript.mdc 保持一致:类型优先、禁止 any、使用 type、枚举用 const 对象等。GestureResponderEvent 等 RN 类型;路由参数使用 Expo Router 提供的类型。// store 状态与类型
export type TodoItem = {
id: string
title: string
done: boolean
}
type TodoState = {
items: TodoItem[]
addTodo: (title: string) => void
toggleTodo: (id: string) => void
removeTodo: (id: string) => void
}
export const useTodoStore = create<TodoState>((set) => ({ ... }))
import { ... } from '@km/shared-utils/universal'。import ... from '@km/shared-utils'(主入口依赖 DOM,在 RN 中会报错)。require('@km/shared-public/images/...') 或 require('@km/shared-public/icons/xxx.png'),与 <Image source={...} /> 配合。react-native-svg-transformer 的前提下,require('@km/shared-public/icons/xxx.svg').default 作为组件使用。className 写 Tailwind 类名(与项目 Tailwind 规范一致,移动优先、语义化间距)。style={[styles.x, { width: w }]})。className;复杂动画或平台差异可用 StyleSheet。className 的断点(如 md:)或条件样式。<View className="flex-1 bg-white items-center justify-center p-6">
<Text className="text-xl mb-6">{greeting}</Text>
<Image source={logo} style={{ width: 128, height: 64 }} />
</View>
todoStore.ts、userStore.ts。create<TState>() 并导出 useXxxStore;状态与 actions 同处一个 slice,避免分散。const { items, addTodo } = useTodoStore();若 store 较大,可用选择器。app/ 下;新页面即新建 app/xxx.tsx 或 app/xxx/index.tsx。<Link href="/path"> 或 router.push('/path');参数与 404 等遵循 Expo Router 约定。_layout.tsx 中统一配置 Stack/Tabs、主题、StatusBar;子目录可再放 _layout.tsx 做嵌套布局。@km/shared-public 引用 icons、images,见上文。assets/,通过相对路径或 require('./assets/...') 引用。react-native-svg + react-native-svg-transformer;仅对来自 shared-public 或本地的 SVG 使用 transformer,避免与 NativeWind 的 Metro 配置冲突。pnpm dev / pnpm start;Web:pnpm web;根目录:pnpm dev:mobile、pnpm dev:mobile:web。pnpm build:shared,再在 apps/mobile 内 pnpm build(expo export)。pnpm type-check(当前使用 --skipLibCheck 规避依赖 .d.ts 问题)。@km/shared-utils/universal 引用工具,未使用主入口。app/ 下,命名与路由一致。pnpm type-check(若可用)。以上为 KM Mobile 开发规范,与 monorepo 内其他规则(如 .cursor/rules/agent.mdc、typescript.mdc)一起使用;在 mobile 范围内的开发以本文档为准。