3、项目初始化与目录结构:用CLI搭好架子,后面才不慌

说实话,很多新手拿到一个移动端CRM项目,第一件事就是急着写代码。我见过不少团队,项目跑起来了,但目录乱得像一锅粥,找文件全靠缘分。嗯,咱们今天就把这第一步走稳了。

我个人习惯是,项目初始化花10分钟,后面能省下10小时。你想想看,一个CRM系统少说几十个页面,上百个组件,目录结构要是没规划好,后期维护起来真的会崩溃。

3.1 使用CLI创建项目

咱们用React Native CLI来创建项目。为什么不用Expo?我在项目中遇到过几次Expo的Native模块限制,后来还是切回了CLI。对于CRM这种需要深度定制的企业级应用,CLI更灵活。

npx react-native init CRMApp --template react-native-template-typescript

这条命令会创建一个带TypeScript模板的项目。如果你用的是RN 0.71以上版本,TypeScript已经是默认配置了,直接这样就行:

npx @react-native-community/cli init CRMApp
我的小建议: 项目名别用中文,也别用下划线。我吃过这个亏,有一次项目名叫"my_crm_app",结果Android打包时各种报错。用驼峰命名最稳,比如"CRMApp"或"MobileCRM"。

3.2 理解项目目录结构

项目创建完后,你会看到一堆文件夹。别慌,咱们一个一个看。说白了,核心就这几个:

CRMApp/
├── android/          # Android原生代码
├── ios/              # iOS原生代码
├── src/              # 咱们的主战场(自己创建)
├── __tests__/        # 测试文件
├── index.js          # 入口文件
├── App.tsx           # 根组件
├── package.json      # 项目配置
├── tsconfig.json     # TypeScript配置
└── babel.config.js   # Babel配置

这里我要重点说一下src/目录。默认项目没有这个文件夹,我建议你手动创建。为什么?因为所有业务代码都应该放在src/里,根目录只放配置文件。这是我踩过坑后养成的习惯。

咱们CRM项目的src/目录,我一般这样组织:

src/
├── components/       # 公共组件
│   ├── common/       # 通用组件(按钮、输入框等)
│   └── business/     # 业务组件(客户卡片、订单列表等)
├── screens/          # 页面
│   ├── Login/        # 登录页
│   ├── Customer/     # 客户管理
│   ├── Order/        # 订单管理
│   └── Dashboard/    # 仪表盘
├── navigation/       # 导航配置
├── services/         # API请求
├── store/            # 状态管理
├── utils/            # 工具函数
├── hooks/            # 自定义Hook
├── types/            # TypeScript类型
└── assets/           # 静态资源

核心原则:按功能模块划分,而不是按文件类型划分。比如把"客户管理"相关的页面、组件、样式都放在一起,而不是把所有页面放一个文件夹,所有组件放另一个。这样找人方便,改起来也快。

3.3 配置package.json

package.json是项目的"身份证"。咱们CRM系统需要安装一些必备依赖。我个人习惯先把这些装上:

{
  "name": "CRMApp",
  "version": "1.0.0",
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint . --ext .ts,.tsx"
  },
  "dependencies": {
    "react": "18.2.0",
    "react-native": "0.72.0",
    "@react-navigation/native": "^6.1.0",
    "@react-navigation/stack": "^6.3.0",
    "axios": "^1.4.0",
    "react-native-vector-icons": "^10.0.0",
    "react-native-safe-area-context": "^4.7.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "@types/react": "^18.2.0",
    "@types/react-native": "^0.72.0",
    "jest": "^29.5.0",
    "@testing-library/react-native": "^12.0.0"
  }
}
注意: 版本号别写死。我曾经把React Native版本写成"0.71.0",结果后来想升级,一堆依赖冲突。用"^"符号表示兼容版本,比如"^0.72.0"表示可以安装0.72.x的最新版本。

这里我解释一下为什么选这些依赖:

  • React Navigation: CRM系统页面多,导航复杂,这个库最成熟
  • Axios: 处理API请求,拦截器做token刷新很方便
  • react-native-vector-icons: 图标库,CRM里各种状态图标用得上

3.4 设置TypeScript

TypeScript对于CRM这种大型项目来说,不是可选项,是必需品。为什么?你想想看,一个客户对象可能有几十个字段,用JS写的话,传参传错了都不知道。TypeScript能在编译时就帮你揪出这些错误。

咱们的tsconfig.json这样配:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "lib": ["es2017"],
    "allowJs": true,
    "jsx": "react-native",
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "babel.config.js"]
}

这里有个关键配置——paths。我设置了@/*指向src/*,这样导入文件时就不用写一长串相对路径了。比如:

// 不用这样写
import { CustomerCard } from '../../components/business/CustomerCard';

// 可以这样写
import { CustomerCard } from '@/components/business/CustomerCard';

嗯,这个配置需要在babel.config.js里也同步一下:

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    [
      'module-resolver',
      {
        root: ['./'],
        alias: {
          '@': './src',
        },
      },
    ],
  ],
};
避坑指南: 我曾经因为忘了配babel的alias,导致路径解析失败,项目直接跑不起来。记住,TypeScript的paths和babel的alias要一起配,缺一不可。

最后,咱们定义几个CRM系统的基础类型。这些类型会贯穿整个项目:

// src/types/index.ts

// 客户信息
export interface Customer {
  id: string;
  name: string;
  phone: string;
  company: string;
  level: 'A' | 'B' | 'C';  // A:高意向 B:中意向 C:低意向
  status: 'new' | 'contacted' | 'negotiating' | 'closed';
  createdAt: string;
  updatedAt: string;
}

// 订单信息
export interface Order {
  id: string;
  customerId: string;
  amount: number;
  status: 'pending' | 'confirmed' | 'shipped' | 'completed';
  items: OrderItem[];
  createdAt: string;
}

// 订单项
export interface OrderItem {
  productId: string;
  productName: string;
  quantity: number;
  price: number;
}

// API响应格式
export interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

有了这些类型定义,后面写业务逻辑时,IDE的智能提示会帮你省下大量时间。说白了,TypeScript就是给你的代码加了一层"安全带",开快车也不怕翻。

好了,项目架子搭好了。下一章咱们开始写第一个页面——登录页。到时候你会感谢今天把目录结构理清楚的自己。