《React Native 0.83 实战:从零构建大厂级工程化模板,一键交付 Android/iOS 双端真机包》

49 阅读25分钟

github项目地址: github.com/nowLetsGoto…

第一步骤: 1.npx react-native@0.83.0 init rn083-app
--template react-native-template-typescript

解释: npx

node自带的临时执行器,不全局安装CLI,原理(npm会下载react-        native@0.83.0,用完即丢,不会污染全局)

--template react-native-template-typescript

使用官方TS模版

如果你想后续用pnpm 下载包,则,可以将npx 换成pnpx

pnpx react-native init MyApp --version 0.83.0 --template react-native-template-typescript 解释: 这行命令会导致,下载ts模版失败

使用官方命令: pnpx @react-native-community/cli init rnAppProject --version 0.83.0 下载正常

这样创建项目就成功了,我们可以进行下载 pnpm install 和cd ios 后 pod install

第二步骤: 我们需要进行工程化,配置项目目录&进行一些工程化配置 rnAppProject/ ├─ src/ # 所有源码 │ ├─ components/ # 可复用组件 │ ├─ screens/ # 页面 │ ├─ hooks/ # 自定义 Hook │ ├─ utils/ # 工具函数 │ ├─ assets/ # 图片、字体等资源 │ └─ navigation/ # React Navigation 配置 ├─ android/ ├─ ios/ ├─ App.js / App.tsx ├─ package.json ├─ tsconfig.json ├─ metro.config.js # Metro 打包配置 └─ README.md

1.安装ts及其相关依赖。

安装 TypeScript 本体

pnpm add -D typescript

解释:typescript:核心编译器,必须。

React Native 的类型定义

pnpm add -D @types/react @types/react-native

解释: @types/react:提供 React 类型支持。 @types/react-native:提供 RN API 类型支持。

这些是必装的,否则你写 JSX、State、Props 都会报类型错误。

TypeScript ESLint 支持

pnpm add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin

eslint:核心 ESLint。 @typescript-eslint/parser:解析 TS 语法。 @typescript-eslint/eslint-plugin:TS 专用规则插件。 作用:TS + ESLint 联动,保证类型和代码风格。

可选依赖(增强 TS 工程化)

ts-node(调试 / 脚本用) pnpm add -D ts-node

直接执行 .ts 文件。

// 待确认

React / React Native ESLint 插件

pnpm add -D eslint-plugin-react eslint-plugin-react-native

eslint-plugin-react:React 专用规则。 eslint-plugin-react-native:React Native 特有规则,如 StyleSheet、组件最佳实践。

插件解释

eslint-plugin-react-native

作用:提供 React Native 特有规则,比如:

检查 StyleSheet 是否合理使用。

禁止硬编码颜色、字体大小等(根据配置)。

提供 RN 性能优化建议。

必要性:

必要:

团队想要统一 RN 代码规范。

想要 ESLint 检查 RN 特有 API 用法,避免性能坑。

可选:

只是小项目,或者团队已有严格的代码 review 流程。

不想被规则限制,想灵活写 RN 代码。

待确认

Prettier + ESLint 联动

pnpm add -D prettier eslint-config-prettier eslint-plugin-prettier

prettier:代码格式化工具。 eslint-config-prettier:禁用 ESLint 与 Prettier 冲突的规则。 eslint-plugin-prettier:让 Prettier 规则作为 ESLint 规则生效。

解释: prettier 核心格式化工具,统一代码缩进、引号、尾逗号等风格 eslint-config-prettier 禁用 ESLint 中可能与 Prettier 冲突的样式规则(如 semi、quotes) eslint-plugin-prettier 把 Prettier 规则作为 ESLint 规则执行,保存或 lint 时自动报错或修复格式问题

场景 是否必要 原因 团队开发 / 工程化项目 ✅ 必须 保证团队代码风格统一,避免格式争议;ESLint + Prettier 联动,保存就能自动格式化 个人项目 / 原型 ⚠️ 可选 可以只用 Prettier 单独格式化,或者用 ESLint 规则处理,没必要强制联动

支持路径别名(@components/@utils 等)

pnpm add -D babel-plugin-module-resolver

import Button from '@components/Button';

到这里基本配置插件下载完了。那么还需要对于 一些文件的配置

tsconfig.json babel.config.js .prettierrc.js .eslintrc.js

1.注意: .vscode 文件目录应该在 项目根目录中,才会对于整个项目的文件进行编辑器设置操作,比如(自动格式化)

2. .vscode/setting.json 文件配置

{ "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": "always", "source.organizeImports": "always" }, "eslint.validate": [ "javascript", "javascriptreact", "typescript", "typescriptreact" ], "java.compile.nullAnalysis.mode": "automatic", "typescript.updateImportsOnFileMove.enabled": "always", "javascript.updateImportsOnFileMove.enabled": "always", "typescript.preferences.importModuleSpecifier": "shortest", "javascript.preferences.importModuleSpecifier": "shortest", "search.exclude": { "/node_modules": true, "ios/Pods": true, "android/build": true }, "files.watcherExclude": { "/node_modules/": true, "ios/Pods/": true, "android/build/**": true }, "files.eol": "\n", "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" } }

  • editor.defaultFormatter : 将工作区的默认格式化器设为 esbenp.prettier-vscode ,即使用 Prettier 来执行“格式化文档”和“保存时格式化”。
  • editor.formatOnSave : 启用“保存时自动格式化”,每次保存时调用默认格式化器对当前文件进行格式化。
  • editor.codeActionsOnSave : 保存时自动执行代码修复动作。
  • source.fixAll.eslint : 触发 ESLint 的“修复所有可修复问题”,包括由 eslint-plugin-prettier 暴露的 Prettier 风格问题。
  • source.organizeImports : 整理导入(移除未使用、去重、按语言服务策略排序)。
  • eslint.validate : 指定由 ESLint 校验的文件类型,覆盖 RN 项目常见前端文件类型: javascript 、 javascriptreact (.jsx)、 typescript (.ts)、 typescriptreact (.tsx)。
  • java.compile.nullAnalysis.mode : Java 的空值分析模式设为 automatic ,当项目存在空注解(如 @Nullable / @NonNull 等)时自动启用相应的空分析,提升原生代码空安全提示。
  • typescript.updateImportsOnFileMove.enabled: "always" 与 javascript.updateImportsOnFileMove.enabled: "always" :移动/重命名文件时自动更新其他文件中的导入路径,避免手工改路径。
  • typescript.preferences.importModuleSpecifier: "shortest" 与 javascript.preferences.importModuleSpecifier: "shortest" :生成更短、更一致的导入路径(在 RN 项目里通常更易读)。
  • search.exclude 与 files.watcherExclude :忽略 node_modules 、 ios/Pods 、 android/build 等大目录,提升搜索与文件监控性能。
  • files.eol: "\n" :统一为 LF 行尾,避免跨平台换行差异造成无意义的 diff。
  • [json] 、 [markdown] 的 editor.defaultFormatter: "esbenp.prettier-vscode" :让 JSON/Markdown 也用 Prettier 格式化,保持风格一致。

注意:

"editor.codeActionsOnSave": { "source.fixAll.eslint": "always", // 处理自动保存eslint格式化, 我设置的always, 也可以设置 explicit "source.organizeImports": "always" // 处理头部导入eslint prettier格式化 },

特殊配置:

typescript.tsdk: "node_modules/typescript/lib" :强制 VS Code 使用工作区的 TypeScript 版本,避免全局 VS Code TS 与项目 TS 版本不一致。

"sonarlint.connectedMode.project": { "connectionId": "https-sonarqube-seakoi-net", "projectKey": "digiziting_client_main_platform_app_65d13ed9-6a86-44d4-9383-9c1d147a5d19" }, SonarLint 连接、cSpell 自定义词典:贴合你团队/个人的质量和拼写校验需求。

tsconfig.json 配置:

{ "compilerOptions": { "target": "ESNext", // 编译输出 ESNext 语法 "module": "ESNext", // 模块规范 "moduleResolution": "node", // Node 风格模块解析 "jsx": "react-jsx", // React 17+ JSX 转换 "strict": false, // 关闭严格模式,按需手动启用 "noImplicitAny": true, // 禁止隐式 any "strictNullChecks": true, // null/undefined 严格检查 "strictBindCallApply": true, // 严格检查函数调用绑定 "strictFunctionTypes": true, // 严格函数类型检查 "strictPropertyInitialization": true, // 类属性初始化检查 "noImplicitThis": true, // this 严格检查 "alwaysStrict": true, // 总是启用严格模式 "allowJs": true, // 支持 JS 文件 "checkJs": false, // 不检查 JS "esModuleInterop": true, // 支持 import x from 'xxx' "forceConsistentCasingInFileNames": true, // 文件名大小写一致 "skipLibCheck": true, // 跳过类型库检查 "resolveJsonModule": true, // 支持 import json "isolatedModules": true, // 单文件编译,配合 Babel "noEmit": true, // 不生成 JS "incremental": true, // 增量编译,加快速度 "types": ["react", "react-native", "jest"], // 全局类型声明 "baseUrl": "src", // 模块别名基准目录 "paths": { // 路径别名 "@components/": ["components/"], "@screens/": ["screens/"], "@utils/": ["utils/"], "@hooks/": ["hooks/"], "@store/": ["store/"] } }, "include": ["src", "index.js", "App.tsx"], // TS 检查的文件 "exclude": ["node_modules", "babel.config.js", "metro.config.js"],

// 增加配置 moduleResolution: "bundler", lib: ["ESNext", "DOM"], "exactOptionalPropertyTypes": true, "noUncheckedIndexedAccess": true, "useUnknownInCatchVariables": true, "noFallthroughCasesInSwitch": true, }

  • 目标与模块
  • target: "ESNext" (rnAppProject/tsconfig.json:4):类型检查按最新 JS 语法期望,配合 Metro/Hermes 没问题。
  • module: "ESNext" (rnAppProject/tsconfig.json:5):保持 ESM 模块语义,利于现代打包器优化。
  • moduleResolution: "node" (rnAppProject/tsconfig.json:6):按 Node 规则解析依赖。
  • JSX
  • jsx: "react-jsx" (rnAppProject/tsconfig.json:7):使用 React 17+ 新 JSX 运行时,减少 import React 的样板。
  • 严格性
  • strict 及一系列 noImplicitAny / strictNullChecks /... (rnAppProject/tsconfig.json:8–15):开启全套严格检查,提升类型安全。
  • JS 互操作
  • allowJs / checkJs (rnAppProject/tsconfig.json:16–17):允许混合 JS,但不对 JS 做类型检查,便于渐进迁移。
  • esModuleInterop (rnAppProject/tsconfig.json:18):改善 CommonJS 与 ESM 的默认导入互操作。
  • 稳定与性能
  • forceConsistentCasingInFileNames / skipLibCheck / incremental (rnAppProject/tsconfig.json:19–20,24):大小写一致、跳过库检查、增量类型分析,加快编辑器速度。
  • isolatedModules / noEmit (rnAppProject/tsconfig.json:22–23):按文件级检查、不产出 JS,和 Babel 流程兼容。
  • resolveJsonModule (rnAppProject/tsconfig.json:21):允许 import JSON。
  • 全局类型与路径别名
  • types: ["react","react-native","jest"] (rnAppProject/tsconfig.json:25):把这三类的全局声明引入到项目。
  • baseUrl: "src" + paths (rnAppProject/tsconfig.json:26–33):提供 @components/* 等别名,提升可读性。
  • 作用域
  • include / exclude (rnAppProject/tsconfig.json:35–36):限定类型检查范围,避免打包/配置文件被 TS 处理。
  • "verbatimModuleSyntax": true, // 区分类型导入与值导入;仅保留运行时需要的导入,要求类型用 import type "exactOptionalPropertyTypes": true, // 可选属性与 undefined 不再互通,严格区分 T | undefined 与 T? "noUncheckedIndexedAccess": true, // 索引访问结果自动含 undefined,例如 arr[i]: T | undefined,促使显式空值处理 "useUnknownInCatchVariables": true, // catch (e) 推断为 unknown,需类型收缩后再使用,更安全 "noFallthroughCasesInSwitch": true, // 禁止 switch case 落空到下一分支,缺少 break/return 会报错

优化建议

  • 依赖解析与库声明

    • 将 moduleResolution 设为 bundler (TS 5+):更好支持现代包的 exports 字段与条件导出,贴近 Metro 打包行为。
    • 明确 lib :设置为 ["ESNext"] ,避免隐式引入 DOM 类型污染 RN 环境(如 Window / document )。
  • 更强的类型安全(按需开启,可能暴露更多问题)

    • exactOptionalPropertyTypes: true :区分可选属性和 undefined 值,减少“漏判”。
    • noUncheckedIndexedAccess: true :索引访问返回值自动变为可能 undefined ,逼迫更安全的访问。
    • useUnknownInCatchVariables: true : catch (e) 推断为 unknown ,避免误用。
    • noFallthroughCasesInSwitch: true :禁止 switch 落空到下一分支。
    • TS 5: verbatimModuleSyntax: true 或 importsNotUsedAsValues: "error" ,强制类型导入用 import type ,与 isolatedModules 更一致。
  • 全局类型作用域(如果不需要测试代码那就不要jest 模块)

    • 将 jest 类型移到测试专用配置(如 tsconfig.test.json )或在 env 控制下启用,避免在应用代码里出现 describe / it 全局污染。
  • 别名与打包一致性

    • 确认 babel.config.js 的 module-resolver 与 tsconfig.paths 一致,否则 Metro 无法识别 TS 侧别名(TS 只影响编辑器和类型检查)。
    • 如需资源别名,补充 @assets/* 、 @services/* 等,保持规范统一。
  • 包管理与版本

    • 保持 typescript.tsdk 指向工作区版本,确保编辑器与构建使用同一 TS 语义。
  • 项目结构

    • 提取基础配置为 tsconfig.base.json ,主配置 extends 它;再为测试、脚本等子场景单独建 tsconfig.test.json 等,便于大项目分层管理。 建议的最小改进片段(供参考)
  • 将这些项加入 compilerOptions :

    • moduleResolution: "bundler"
    • lib: ["ESNext"]
    • 可选严格项: exactOptionalPropertyTypes: true 、 noUncheckedIndexedAccess: true 、 useUnknownInCatchVariables: true 、 noFallthroughCasesInSwitch: true
    • TS 5 路线: verbatimModuleSyntax: true
  • 将 types 中的 jest 挪到测试专用 tsconfig.test.json ,主 tsconfig.json 保留 react / react-native 即可。

  • 在 babel.config.js 增加与 paths 对齐的 module-resolver 映射,以保证运行时可解析。

注意事项

  • 加强严格选项会让编辑器报告更多潜在问题;建议先在新/关键模块启用,逐步推广。
  • 别名需要 Babel/Metro 同步配置;仅改 tsconfig 不会影响运行时解析。
  • RN 不存在浏览器 DOM 环境;去掉 DOM 类型能更早发现使用了非 RN 能力的代码。

babel.config.js 配置

module.exports = { presets: [ 'module:metro-react-native-babel-preset', // RN 官方推荐 Babel 预设,支持最新 JS、JSX、TS ], plugins: [ [ 'module-resolver', // 路径别名插件 { root: ['./src'], // 根目录,和 tsconfig.json 的 baseUrl 对齐 alias: { '@components': './src/components', '@screens': './src/screens', '@utils': './src/utils', '@hooks': './src/hooks', '@store': './src/store', '@assets': './src/assets', }, extensions: ['.js', '.ts', '.tsx', '.jsx', '.json'], // 支持解析的文件类型 }, ], 'react-native-reanimated/plugin', // 如果使用 Reanimated 动画库必须放在最后 ], };

优化后:

module.exports = { presets: [ 'module:@react-native/babel-preset', // RN 官方推荐 Babel 预设,支持最新 JS、JSX、TS ], plugins: [ 'babel-plugin-macros', [ 'module-resolver', // 路径别名插件 { root: ['./src'], // 根目录,和 tsconfig.json 的 baseUrl 对齐 alias: { '@': './src', '@components': './src/components', '@screens': './src/screens', '@utils': './src/utils', '@hooks': './src/hooks', '@store': './src/store', '@assets': './src/assets', }, extensions: [ '.ios.ts', '.ios.tsx', '.android.ts', '.android.tsx', '.native.ts', '.native.tsx', '.js', '.ts', '.tsx', '.jsx', '.json', ], // 支持解析的文件类型 }, ], [ 'module:react-native-dotenv', { envName: 'APP_ENV', moduleName: '@env', path: '.env', }, ], 'react-native-reanimated/plugin', // 如果使用 Reanimated 动画库必须放在最后 ], env: { production: { plugins: [ ['transform-remove-console', { exclude: ['error', 'warn'] }], 'babel-plugin-dev-expression', ], }, }, };

优化建议

  • macros :为诸如 styled-components/macro 、 linaria 、 emotion 、 immer 等宏提供支持;未使用也无副作用。
  • 平台扩展:确保在有同名平台文件时优先解析平台特定实现,减少条件分支和运行时判断。
  • @ 别名:更短路径别名,与 tsconfig.json 的 baseUrl: "src" 一致,统一导入风格。
  • 生产移除 console :压缩生产包体、减少 JS 线程压力;保留 error / warn 便于线上定位问题。
  • dev-expression :将 process.env.NODE_ENV 等开发分支常量化,有利于打包阶段的无用代码消除,减小构建体积。

配置解释:

  • presets: ['module:@react-native/babel-preset']

    • 使用 RN 官方预设,内含 TS/JS/JSX 必要语法转换,适配 Metro/Hermes。
  • plugins: ['babel-plugin-macros', ...]

    • 启用宏语法支持;若代码中使用宏,Babel 会在编译期展开以提升性能和可读性。
  • plugins: [['module-resolver', { root, alias, extensions }]]

    • root: ['./src'] :将 src 作为模块解析基准目录。
    • alias :声明路径别名, '@' 指向根目录,其余指向各子目录,简化导入。
    • extensions :声明解析扩展名顺序;平台扩展放在前面,确保按平台优先选择对应文件,其后为通用扩展。
  • plugins: ['react-native-reanimated/plugin']

    • Reanimated 必须置于插件链末尾,以确保其编译阶段代码注入与优化正常,(自行确定是否需要)
  • env.production.plugins: [['transform-remove-console', { exclude: ['error', 'warn'] }], 'babel-plugin-dev-expression']

    • 生产构建时移除 console.log/info/debug 等,保留 warn/error 。
    • 常量折叠开发/生产分支,利于 dead-code elimination,减小包体与运行时分支。 与现有 tsconfig 的一致性
  • module-resolver.root / alias 与 tsconfig.json 的 baseUrl: "src" 、 paths 语义对齐,编辑器与运行时解析一致,避免“编辑器能跳但运行时报错”。 可选增强(按需)

  • 如果你希望彻底清除生产 console ,去掉 exclude 。

注意:

root: ['./src', './base', './config', './module', './outModule'], 可以配置多个引入到的根目录路径

精简 module-resolver extensions 的图片后缀

  • 建议移除 .png/.jpg/.gif/.svg/.webp/.jpeg

  • 理由:Metro 的资产系统在打包阶段处理图片;Babel 的 module-resolver 仅处理 JS/TS 导入路径,图片扩展在此处通常无效且易误导。

  • root 建议以 ['./src'] 为主;其余目录用明确别名引用

  • 确保 tsconfig.json 的 baseUrl 与 paths 与 Babel alias 一致

  • 理由:统一编辑器与运行时解析,避免“编辑器可跳、运行时报错”的不一致。

dotenv 使用建议

  • 保持 module:react-native-dotenv,moduleName 为 @env

配置意图

  • 使用 Babel 插件把 .env 中的变量在编译期注入到代码里,通过 @env 模块导入,避免在运行时从进程环境读取,适合 React Native。 各字段含义

  • 'module:react-native-dotenv' :启用 dotenv 的 Babel 插件;把 import { VAR } from '@env' 转换为常量值。

  • envName: 'APP_ENV' :

    • 指定用哪个环境变量名来选择 .env 文件的后缀,例如 APP_ENV=staging 会读取 .env.staging 。
    • 作用是独立于 NODE_ENV 控制环境文件选择,解决 Metro/测试覆盖问题。
  • moduleName: '@env' :

    • 规定导入时使用的虚拟模块名,例如 import { API_URL } from '@env' 。
    • Babel 在编译时把它替换为对应的常量值。
  • path: '.env' :

    • 指定基础 .env 文件路径;支持多环境合并( .env , .env. , .env.local 等)。

    依据官方说明,使用 APP_ENV 时不要用 development / production 作为值,也不要命名 .env.development / .env.production (与 Babel/Node 的保留语义冲突)[npm 文档引用]。

.prettierrc.js 配置

module.exports = { printWidth: 100, // 一行最大字符数,超过换行。团队协作推荐 100,避免行太长影响阅读 tabWidth: 2, // 一个 tab 相当于几个空格,这里统一 2 空格 useTabs: false, // 是否使用 tab 缩进,这里使用空格,更普遍且兼容性好 semi: false, // 语句末尾强制使用分号,避免自动插入带来的潜在 bug singleQuote: true, // 字符串使用单引号,统一风格,避免双引号/单引号混用 trailingComma: 'all', // 多行对象、数组末尾加逗号,减少 git diff 干扰 bracketSpacing: true, // 对象字面量的大括号内加空格 { foo: bar },提高可读性 arrowParens: 'always', // 箭头函数参数总是加括号,避免歧义和代码风格不一致 endOfLine: 'lf', // 换行符使用 LF,统一跨平台(避免 Windows CRLF 和 Mac/Linux LF 不一致) jsxSingleQuote: false, // JSX 中仍使用双引号,保持 React 官方习惯 proseWrap: 'never', // markdown 或字符串不自动换行,团队协作更可控 htmlWhitespaceSensitivity: 'css', quoteProps: 'as-needed', // 对象属性仅在必要时加引号 { foo: 1 } 而不是 { "foo": 1 } bracketSameLine: false, // JSX 标签的 > 单独占一行,保持可读性 embeddedLanguageFormatting: 'auto', // 支持格式化内嵌语言,比如 CSS in JS 或 GraphQL singleAttributePerLine: true, // JSX/Vue/HTML 在多行时每行一个属性,提升可读性与 diff 友好 overrides: [ { files: ['.json'], options: { parser: 'json' }, }, { files: ['.jsonc', '.json5'], options: { parser: 'json5' }, }, ], plugins: ['@trivago/prettier-plugin-sort-imports'], importOrder: [ '^react,react/(.)', '^react/(.*)', '^react-native,reactnative/(.)', '^react-native/(.*)', '^@react-navigation/(.),@reactnative/(.)', '^@react-native/(.*)', '^@ant-design/(.),antd', '^antd', '^antd/(.),<THIRDPARTYMODULES>,@config/(.)', '<THIRD_PARTY_MODULES>', '^@config/(.*)', '^@base/(.),@module/(.)', '^@module/(.*)', '^@equality,@equality/(.)', '^@equality/(.*)', '^@supply,@supply/(.)', '^@supply/(.*)', '^@marketing,@marketing/(.)', '^@marketing/(.*)', '^@outModule/(.),@/api', '^@/api', '^@/api/(.),@/store', '^@/store', '^@/store/(.),@/router', '^@/router', '^@/router/(.),@/hooks', '^@/hooks', '^@/hooks/(.),@/utils', '^@/utils', '^@/utils/(.),@/constants', '^@/constants', '^@/constants/(.),@/types', '^@/types', '^@/types/(.),@/assets', '^@/assets', '^@/assets/(.),@/pages', '^@/pages', '^@/pages/(.),@/demo', '^@/demo', '^@/demo/(.),@/components', '^@/components', '^@/components/(.),@/(.)', '^@/(.*)', '^[./].\.(css|less|scss|sass|styl),[./]..(pngjpgjpeggifsvgwebpicobmptiff)', '^[./].*\\.(png|jpg|jpeg|gif|svg|webp|ico|bmp|tiff)', '^[./].*\.(woff|woff2|ttf|eot)$', '^[./]', ], importOrderSeparation: false, importOrderSortSpecifiers: true, importOrderCaseInsensitive: true, importOrderGroupNamespaceSpecifiers: true, importOrderBuiltinModulesToTop: true, };

配置解释:

可优化项

  • singleAttributePerLine: true

  • 建议保持现有的 LF、trailingComma、semi、singleQuote 等,与你的团队习惯一致,不改动 为什么加 singleAttributePerLine

  • 提升 JSX/HTML/Vue 多行属性的可读性:长组件属性在多行时,每行一个属性更易审阅。

  • 改善 diff 效果:新增/删除单个属性只影响一行,减少混合改动。

  • 与主流风格指南(如 Airbnb)一致,Prettier 2.6+支持该选项。 当前配置效果说明

  • printWidth: 100:控制每行长度,便于在 RN 视图和 Hook 中阅读长表达式。

  • tabWidth: 2、useTabs: false:统一 2 空格缩进,兼容多数编辑器与工具链。

  • semi: true:语句以分号结尾,避免 ASI(自动插入分号)造成的边界问题。

  • singleQuote: true:字符串统一单引号,减少混用带来的风格噪音。

  • trailingComma: 'all':对象/数组/参数列表末尾保留逗号,优化增删项的 diff。

  • bracketSpacing: true:对象字面量内两侧空格,提高可读性。

  • arrowParens: 'always':始终为箭头函数参数加括号,避免一参省略带来的歧义。

  • endOfLine: 'lf':统一 LF,避免跨平台 CRLF 差异。

  • jsxSingleQuote: false:JSX 属性使用双引号,贴近 React 社区习惯。

  • proseWrap: 'never':不自动换行 Markdown/长文本,团队协作时更可控。

  • quoteProps: 'as-needed':仅必要时为对象键加引号,JSON 仍按规范使用双引号。

  • bracketSameLine: false:JSX 闭合尖括号独立一行,结构更清晰。

  • embeddedLanguageFormatting: 'auto':自动格式化内嵌语言(CSS-in-JS、GraphQL 等)。

  • singleAttributePerLine: true:多行时每行一个属性,提升阅读与 diff 质量。

    • htmlWhitespaceSensitivity: 'css'
  • 明确按照 CSS 规则处理 HTML 空白敏感性,避免不期望的空白折叠差异;该值与 Prettier 默认一致,但显式声明更清晰,团队可读性更强。

  • overrides 针对 JSON/JSONC/JSON5

  • 保证 JSON 文件严格使用 JSON 语法格式化,避免非标准内容引入。

  • 对含注释或更宽松语法的 JSONC/JSON5 文件采用 json5 解析器,防止格式化时报错或误删注释。

  • 插件依赖未就绪:你的导入排序依赖的是 @trivago/prettier-plugin-sort-imports。工作区原本没有这个插件,直接启用会导致 Prettier 报错。

  • 规避冲突:导入排序也常由 ESLint 接管(如 simple-import-sort)。为避免 Prettier 与 ESLint“双管齐下”造成互相回改,先确认用哪条路径更稳妥。 已为你加上

  • 在 .prettierrc.js 中加入导入排序插件与规则,并补充解析兼容项:

    • .prettierrc.js
  • 在 package.json 增加插件依赖:

    • package.json 你现在可以安装依赖后使用:
  • npm i 或 pnpm i 或 yarn 具体配置与意义

  • plugins: ['@trivago/prettier-plugin-sort-imports']

    • 在格式化时对 import 顺序进行重排,保障导入分组与顺序一致。
  • importOrder: [...你的分组...]

    • 分层排序:React/RN → UI → 第三方 → 配置/基础/业务/外部模块 → 核心源码(@/...)→ 样式/资源 → 相对路径
    • 优点:导入结构清晰,代码审阅更可读。
  • importOrderSeparation: false

    • 分组之间不空行;如需更清晰的分组视觉,可改为 true。
  • importOrderSortSpecifiers: true

    • 命名导入内部按字母排序;保证稳定排序。
  • importOrderCaseInsensitive: true

    • 忽略大小写排序;避免因不同大小写导致排序波动。
  • importOrderGroupNamespaceSpecifiers: true

    • 将 namespace 导入单独分组;提高条理性。
  • importOrderBuiltinModulesToTop: true

    • Node 内置模块(fs、path 等)置顶;保持专业排序习惯。

.eslintrc.js 配置

import js from '@eslint/js' import globals from 'globals' import tseslint from 'typescript-eslint' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' import reactNative from 'eslint-plugin-react-native' import unusedImports from 'eslint-plugin-unused-imports' import prettier from 'eslint-plugin-prettier' import { globalIgnores } from 'eslint/config' import { fixupPluginRules } from '@eslint/compat'

export default tseslint.config([ globalIgnores([ '/node_modules/', '/android/build/', '/ios/Pods/', '/dist/', '/build/', '/coverage/', '/public/', '/static/', '/*.min.js', '/.min.css', ]), js.configs.recommended, { files: ['**/.{js,cjs}'], languageOptions: { parserOptions: { ecmaVersion: 'latest', sourceType: 'commonjs', }, globals: { ...globals.node, ...globals.commonjs }, }, rules: { 'no-console': 'off', 'no-undef': 'off', 'no-redeclare': 'off', 'no-unused-vars': 'off', }, }, { files: ['**/*.{ts,tsx,mts,cts}'], extends: [ ...tseslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, ], plugins: { react, 'react-hooks': reactHooks, 'react-native': fixupPluginRules(reactNative), 'unused-imports': unusedImports, prettier, }, settings: { react: { version: 'detect' }, }, languageOptions: { parserOptions: { ecmaVersion: 'latest', sourceType: 'module', projectService: true, tsconfigRootDir: import.meta.dirname, }, globals: { ...globals.node, ...globals.es2021 }, }, rules: { 'prettier/prettier': ['error'], 'react/react-in-jsx-scope': 'off', 'react/jsx-uses-react': 'off', 'react/prop-types': 'off', 'react/no-unstable-nested-components': ['error', { allowAsProps: true }], 'unused-imports/no-unused-imports': 'error', 'unused-imports/no-unused-vars': [ 'warn', { args: 'after-used', argsIgnorePattern: '^', varsIgnorePattern: '^' }, ], '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-floating-promises': 'warn', '@typescript-eslint/no-misused-promises': 'warn', '@typescript-eslint/await-thenable': 'warn', '@typescript-eslint/no-unused-expressions': [ 'error', { allowShortCircuit: true, allowTernary: true, allowTaggedTemplates: false }, ], '@typescript-eslint/prefer-optional-chain': 'error', '@typescript-eslint/no-redeclare': ['error', { ignoreDeclarationMerge: false }], 'react-native/no-unused-styles': 'error', 'react-native/no-raw-text': ['error', { skip: ['XZLText'] }], 'react-native/no-inline-styles': 'off', 'react-native/split-platform-components': 'error', camelcase: 'warn', 'default-case': 'error', 'no-duplicate-imports': 'error', 'no-unreachable': 'error', eqeqeq: ['error', 'always', { null: 'ignore' }], }, }, ])

解释配置

  • 合并你的优点到当前配置:

    • 新增 CommonJS 文件块:files: ['**/*.{js,cjs}'],sourceType: 'commonjs',globals 使用 node/commonjs
    • 补充 TS 规则:'@typescript-eslint/no-redeclare': ['error', { ignoreDeclarationMerge: false }]
  • 保留并强化现有优势:

    • 类型感知:...tseslint.configs.recommendedTypeChecked + no-floating-promises/no-misused-promises/await-thenable
    • 未使用项:unused-imports 接管导入与变量治理
    • RN 质量:no-unused-styles/no-raw-text(跳过 XZLText)/split-platform-components: error
    • 测试隔离:Jest 推荐规则与环境
    • Prettier 联动:prettier/prettier 错误级别 代码位置
  • eslint.config.js 区别与取舍

  • 你的版本

    • 在 TS 块里使用了 reactHooks.configs['recommended-latest'];我们用 react-hooks 推荐规则并与 React 推荐规则合并,效果等价。
    • 你把 CommonJS 配置覆盖到 ts/js;我们仅针对 js/cjs 做 commonjs,避免 TS 模块解析冲突。
    • 使用 globals.es2022;我们采用 es2021 以规避声明提示(IDE/类型提示更干净)。
    • no-unused-vars: error;我们用 unused-imports 接管,导入与变量更精准,且支持下划线忽略。
  • 当前版本(优化后)

    • 拆分 CommonJS 与 Module,保持 TS/JS 模块语义清晰。
    • 类型感知规则集更全,异步安全覆盖更强。
    • 测试与格式化联动更明确。 关键配置解析
  • 顶层继承

    • js.configs.recommended:启用 JS 推荐基础规则
    • ...tseslint.configs.recommended / recommendedTypeChecked:启用 TS 推荐与类型感知规则集
  • globalIgnores([...])

    • 忽略依赖/构建产物/静态目录,提升速度并减少无效校验
  • CommonJS 文件块

    • files: ['**/*.{js,cjs}'] + sourceType: 'commonjs':Node/打包脚本保持 CJS 解析,允许 require 等
  • TS/React/RN 文件块

    • plugins: react/react-hooks/react-native/unused-imports/prettier
    • languageOptions.parserOptions:projectService + tsconfigRootDir,启用类型感知
    • settings.react.version: 'detect':自动适配 React 版本
  • 规则(精选)

    • 'prettier/prettier': 'error':格式化差异直接报错
    • 'unused-imports/no-unused-imports': 'error':移除未使用导入
    • 'unused-imports/no-unused-vars': ['warn', { argsIgnorePattern: '^ ', varsIgnorePattern: '^ ' }]:变量治理,支持下划线忽略
    • '@typescript-eslint/no-floating-promises' / 'no-misused-promises' / 'await-thenable': 'warn':异步安全
    • '@typescript-eslint/no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }]:表达式安全
    • '@typescript-eslint/prefer-optional-chain': 'error':鼓励可选链
    • '@typescript-eslint/no-redeclare': ['error', { ignoreDeclarationMerge: false }]:防重复声明,避免命名空间/类型合并误用
    • 'react/no-unstable-nested-components': ['error', { allowAsProps: true }]:限制不稳定嵌套组件
    • 'react-native/no-unused-styles': 'error'、'react-native/no-raw-text': ['error', { skip: ['XZLText'] }]、'react-native/split-platform-components': 'error'
    • 'camelcase': 'warn'、'default-case': 'error'、'no-duplicate-imports': 'error'、'no-unreachable': 'error'、'eqeqeq': ['error', 'always', { null: 'ignore' }]
  • 新增插件与规则

    • 插件:jest、unused-imports
    • 规则:
      • 关闭 @typescript-eslint/no-unused-vars,改用 unused-imports/no-unused-imports 与 unused-imports/no-unused-vars
      • 开启 reportUnusedDisableDirectives: true
  • 增加 overrides

    • 测试文件:启用 plugin:jest/recommended 并设置 env: { jest: true }
    • TS 文件:启用 plugin:@typescript-eslint/recommended-requiring-type-checking,开启 no-floating-promises、no-misused-promises、await-thenable
    • 为类型检查规则指定 parserOptions.project: ['./tsconfig.json']
  • 增加 ignorePatterns

    • 忽略 node_modules、android/build、ios/Pods、dist、build 等 代码位置:
  • .eslintrc.js

  • package.json 配置意义与作用

  • plugins: ['jest', 'unused-imports']

    • jest:提供针对测试的规则(断言风格、测试结构正确性)。
    • unused-imports:更精确地检测并移除未使用的导入与变量。
  • 关闭 '@typescript-eslint/no-unused-vars',启用 unused-imports/no-unused-*

    • 避免重复提示与冲突,由 unused-imports 统一治理未使用项,更贴合现代项目实践;支持忽略下划线前缀变量。
  • reportUnusedDisableDirectives: true

    • 对无效或多余的 eslint-disable 进行提示,避免遗留的禁用指令掩盖问题。
  • overrides(测试)

    • extends: ['plugin:jest/recommended'] + env: { jest: true }:对测试用例启用更合理的校验(如不正确的断言、未使用的测试等),并提供 Jest 全局环境。
  • overrides(TS 类型感知)

    • extends: ['plugin:@typescript-eslint/recommended-requiring-type-checking']:开启类型驱动的高级规则
      • '@typescript-eslint/no-floating-promises':防止丢弃未处理的 Promise
      • '@typescript-eslint/no-misused-promises':避免把 Promise 误用于非异步上下文(如事件处理器)
      • '@typescript-eslint/await-thenable':确保 await 用于真正的 Thenable
    • parserOptions.project:指向 tsconfig.json,使类型感知规则生效
  • ignorePatterns

    • 忽略大型或生成目录,提升 ESLint 速度,减少无意义校验 保留与对齐
  • 继续使用 React、React Hooks、React Native 推荐规则和 Prettier 联动,保证风格一致与 RN 场景校验。

  • 与已配置的 Prettier、路径别名、Babel 环境共同工作,避免工具之间的冲突。 为什么这样优化

  • 未使用治理更精准:unused-imports 在大型 RN 项目里更稳,能同时处理导入与变量,减少手工清理。

  • 类型感知的异步安全:RN 中网络/Storage/动画等大量异步逻辑,类型驱动规则更容易发现潜在问题(未 await、滥用 Promise)。

  • 测试隔离:让测试文件有专属的规则和环境,避免把测试特性引入应用代码。

  • 性能与清晰度:忽略无关目录,避免浪费时间在第三方或构建产物上;禁用指令校验阻止“无效忽略”长期存在。

注意配置:

  • 在 CommonJS 文件块中新增规则,位置: eslint.config.js

  • rules:

    • 'no-console': 'off'
    • 'no-undef': 'off'
    • 'no-redeclare': 'off'
    • 'no-unused-vars': 'off' 为什么这样配
  • 允许 require/console 等 CJS 习惯用法:

    • 在 Node/CommonJS 脚本、打包配置、工具脚本里普遍使用 require、module.exports、console。关闭这些限制避免无意义告警。
  • 避免与 TS/模块语义冲突:

    • CommonJS 块仅匹配 js/cjs 文件;TS/ESM 规则保留在 TypeScript 文件块中,分层管理更清晰。
  • 提升开发效率:

    • 这些脚本通常非应用运行路径,宽松校验减少干扰;业务代码的严格校验仍由 TS/React/RN 块负责。 具体意义
  • 'no-console': 'off'

    • 允许在 CJS 脚本中使用 console 输出(日志/调试/脚本提示)。
  • 'no-undef': 'off'

    • 在已声明 Node/CommonJS 全局的前提下,避免对 process、__dirname、module、require 等报未定义。
  • 'no-redeclare': 'off'

    • 在某些脚本中允许重复声明(如基于条件或构建层复用变量的写法),减少误报。
  • 'no-unused-vars': 'off'

    • CJS 工具脚本里未使用变量经常是临时或占位,关闭未使用检测避免噪音;业务代码里未使用项仍由 unused-imports 规则治理。

进一步需要下载的 插件

pnpm add -D babel-plugin-macros pnpm add -D react-native-dotenv babel-plugin-transform-remove-console babel-plugin-dev-expression

  • babel-plugin-macros: 让支持 “宏” 的库通过特殊 import 语法在编译期展开代码,零配置接入。很多生态库(例如 styled-components/macro、linaria、emotion 等)依赖它;如果项目或其依赖链中引用了宏语法但未安装该插件,打包会直接报错。
  • module:react-native-dotenv: 允许从 .env 文件中按模块方式读取环境变量,在 JS/TS 里通过 @env 导入,避免手写 process.env 并简化 RN 环境注入。
  • babel-plugin-transform-remove-console: 在生产环境删除 console 调用(可保留 error/warn),缩小包体、减少运行时开销。
  • babel-plugin-dev-expression: 在生产环境把 DEV 分支“剪掉”(死代码消除),进一步减小产物体积并避免执行开发专用逻辑。

下载的理由:

项目中的使用

  • 当前已在配置中启用这些插件,且会生效:
    • 在 babel.config.js 明确启用了 babel-plugin-macros。
    • dotenv 插件配置在 babel.config.js 。
    • 生产优化插件在 babel.config.js 的 production 环境下生效。
  • 代码里目前还没有直接使用 @env 或宏语法的导入,因此:
    • babel-plugin-macros 安装后不影响未使用宏的文件,但它是必要的基础设施,之前 Metro 的“找不到 babel-plugin-macros”报错就是因为缺少它。
    • react-native-dotenv 现在是“可用但未使用”。你可以随时开始用它来管理敏感配置或多环境变量。

使用的案例:

如何在代码中使用

  • 读取环境变量(已可用,按需添加到 .env):
import { API_URLSENTRY_DSN } from '@env';
// 使用时与普通常量一致
fetch(`${API_URL}/todos`);
  • 删除生产环境 console(已自动生效,无需改代码):

    • 开发环境保留全部 console;
    • 生产环境仅保留 console.error 和 console.warn(按配置)。
  • 剪除 DEV 分支(已自动生效):

if (__DEV__) {
  // 这里的代码在生产构建时会被移除
}
  • 宏语法(目前未使用,示例说明用途):
// 例如使用 styled-components/macro 时,编译期会做更激进优化
import styled from 'styled-components/macro';

为何需要安装这些依赖

  • 这些插件在 babel.config.js 中已经声明,如果不把它们列为依赖,Metro/打包会因为“找不到插件”而失败(之前的报错即是如此)。
  • transform-remove-console 与 dev-expression 只在生产环境启用,对开发流程无侵入;但它们显著优化发布包体积与性能。
  • react-native-dotenv 为大项目提供标准化的环境变量注入方式,避免把配置硬编码到源码或自行实现不稳定的注入逻辑。 结论与建议
  • 以上插件都“用得上”:macros 是为依赖链兜底,dotenv 为环境管理预置能力,另外两个是生产优化插件。
  • 保留这些配置是合理的;如果你暂时不需要环境变量,可以先不在代码里引 @env,但建议保留插件,随时可用且不会造成负担。

下载其他插件

pnpm add @react-navigation/native @react-navigation/native-stack react-native-screens @react-native-async-storage/async-storage pnpm add -D globals

解释下载插件

  • @react-navigation/native: React Native 的路由核心库,提供 NavigationContainer、导航状态与生命周期管理。
  • @react-navigation/native-stack: 基于原生视图的栈导航(Native Stack),推拉式页面切换更快,更符合移动端体验。
  • react-native-screens: 将导航屏幕用原生容器承载,减少 JS 帧负担,显著提升导航性能;与 Native Stack 搭配使用。
  • @react-native-async-storage/async-storage: 持久化存储库,用于保存登录 token、用户偏好等到本地(App 重启也能读取)。
  • globals(开发依赖): 为 ESLint Flat Config 提供标准环境全局变量集合(如 browser、es2021),用来配置解析器认识的全局名,避免未定义变量的误报。

其他配置:

  • 开启 Web API 类型声明: React Native 提供 fetch、AbortController、Headers、Response、FormData 等“类浏览器”API,这些类型都在 DOM 类型库里。加入 DOM 后,TypeScript能正确识别这些全局与接口,避免类型报错。

  • 适配我们新增的请求封装: 在请求封装里使用了 AbortController、Response 和 FormData,若不包含 DOM,TS 会缺少这些类型,影响类型检查与开发体验。参考 api.ts 的 AbortController、以及响应处理 api.ts 。

  • 保持现代语法支持: ESNext 保留最新的语言特性类型;DOM 仅补充 Web API 的类型声明,不会把浏览器的真实 DOM 注入到 RN 运行时。 不会带来的影响

  • 不会引入真实浏览器 DOM: 这只是类型层面的补充,RN 仍然没有 document/window 等真实 DOM;代码运行环境不变。

  • 避免 Node 类型冲突: 当前未引入 Node 类型库(如 node),并且使用 bundler 模块解析,通常不会与 DOM 类型产生冲突。 可选优化

  • 如果代码里需要迭代器相关的 DOM 类型(如 Headers/URLSearchParams 的迭代),可追加 DOM.Iterable:比如 "lib": ["ESNext", "DOM", "DOM.Iterable"]。目前你的代码不强依赖它,保持现状即可。 配置位置

  • 已在 tsconfig.json 设置 "lib": ["ESNext", "DOM"],以满足 RN 环境下的 Web API 类型需求。

tsconfig.tsbuildinfo 文件作用:

  • 增量编译缓存文件: 当 TypeScript 开启增量编译时,会生成 tsconfig.tsbuildinfo,记录上次编译的依赖图、版本、文件时间戳等元数据。

  • 加速类型检查/编译: 有了该缓存,下一次只重新检查变更过的文件,大幅减少 tsc 的耗时。

  • 自动生成与使用: 每次运行 tsc(或 IDE 后台类型检查)都会读取/更新它,无需手动维护。 为何出现

  • 你的配置开启了增量编译,见 tsconfig.json 的 incremental: true,所以 tsc 会生成这个文件, 会生成 tsconfig.tsbuildinfo 文件 是否需要提交到仓库

  • 通常不需要。它是构建工件,建议加入 .gitignore(很多项目默认忽略)。

  • 删除它是安全的:下次类型检查会重新生成,但那次会是一次“完整检查”,时间稍长。 进阶设置

  • 自定义文件位置: 通过 tsBuildInfoFile 指定路径,例如设置为 .tsbuildinfo,便于统一管理。

  • 关闭增量编译: 如果不想生成该文件,可在 tsconfig 把 incremental 设为 false;但会失去加速收益。 与 RN 的关系

  • RN 运行时依赖 Babel 转换,tsc 在本项目主要用于类型检查(你运行过 tsc --noEmit)。即使不发出 JS,增量模式仍会写入 tsbuildinfo,以加速后续检查。

其他功能

.npmignore,这是按你提出“加入发布忽略清单(不提交、不打包)”的要求做的,用于在打包/发布阶段排除增量编译缓存文件。文件位置在 .npmignore 。

  • 用途: 在 npm/pnpm 的 pack/publish 流程中,.npmignore 控制打包的忽略项;没有 .npmignore 时会 fallback 用 .gitignore。明确添加它可以确保 tsconfig.tsbuildinfo 和 *.tsbuildinfo 不会进入发布包。
  • 对运行无影响: 它只影响打包产物的内容,不影响开发或运行。即使你的项目只是 App 而不是要发布的库,保留它也没有副作用。
  • 可选替代方案: 未来如果更偏好用 package.json 的 files 白名单来控制发布范围,也可以把忽略逻辑改为 files 管理,我可以帮你切换并移除 .npmignore。

工程化:

代码质量

  • 强约束 TypeScript:开启更严格的编译选项(保持 noUncheckedIndexedAccess、exactOptionalPropertyTypes、useUnknownInCatchVariables 等),为 API 层和组件 props 设定显式类型

  • Lint 组合:ESLint 9 Flat Config + typescript-eslint typed rules 分区生效;Prettier 统一格式;import 排序插件维持稳定 diff

  • 自动修复与检查:在 CI 中运行 pnpm run lint、pnpm exec tsc --noEmit,阻止不合规的变更进入主分支 提交与钩子

  • 预提交钩子:husky + lint-staged 在提交前只格式化与 Lint 受影响的改动文件,保证提交质量和速度

  • 提交规范:commitlint + conventional commits(feat/fix/chore…)用于生成变更日志与自动版本管理

  • 分支策略:主分支保护、必须通过 CI、强制评审;release 分支用于封版 测试体系

  • 单元测试:Jest + React Native Testing Library,覆盖 UI、hooks、纯逻辑;对 API 封装做成功/错误/超时分支测试

  • 端到端测试:Detox 做登录流程与导航跳转的端到端验证;覆盖关键用户路径

  • 覆盖率门槛:在 CI 强制 lines/branches/functions 达到约定阈值(如 ≥80%) CI/CD

  • 持续集成:GitHub Actions 或其他 CI,分离 Job(typecheck、lint、test、android build、ios build),启用缓存(pnpm store、Gradle configuration cache)

  • 持续交付:fastlane 自动化打包签名、上传商店或分发渠道;支持渠道化与多环境

  • 构建矩阵:Android/iOS 同步构建,针对 dev/staging/prod 使用不同证书与环境注入 配置与环境

  • 环境变量管理:统一在 .env.{env} 中维护,约定只读型与敏感型;使用 @env 或 react-native-config 注入;为变量建立类型声明(你已添加 src/types/env.d.ts)

  • 配置分层:区分运行时配置(接口域名、开关)和编译期配置(特性开关),避免把机密写死在源码

  • 产物忽略:.gitignore 与 .npmignore 已忽略 tsbuildinfo 与构建工件;如发布为库可改用 package.json files 白名单 构建与发布

  • 多环境构建:Android Gradle flavors、iOS Schemes,对应 dev/staging/prod 包名、图标、权限

  • 版本与渠道:自动递增版本号(语义化版本),渠道包差异(资源、开屏、埋点)

  • 资源生成:自动生成图标与启动图(如使用 tools/脚本),统一尺寸与规范 运行时质量

  • 崩溃与性能:集成 Sentry(或 Firebase Crashlytics)做崩溃与异常上报;Flipper 监控网络、性能、布局

  • 日志与埋点:结构化日志(级别、事件);行为埋点与风控;对隐私信息脱敏

  • OTA 更新:按需使用 CodePush(AppCenter)在灰度场景下做热更新与回滚策略 网络与数据

  • API 客户端:你已封装通用 request(超时、HTTP/网络错误、token 注入);建议加入重试策略、幂等控制、取消并发、错误分级(提示/静默/重试)

  • 缓存与状态:Query 层(React Query 或 SWR)做数据缓存、重试、失效管理;全局状态(Redux Toolkit/Zustand)用于登录态与 app 设置

  • 安全与合规:启用 HTTPS、按需 TLS/证书钉扎、网络权限最小化、敏感信息不写日志 导航与体验

  • 深链与路由守卫:处理外部 deep link、基于 token 的路由守卫(未登录跳转 Login);404/错误页

  • 国际化与无障碍:react-native-localize + i18next;无障碍标签、字号适配;RTL 支持

  • 布局适配:安全区(你已用 react-native-safe-area-context)、键盘与输入法适配、分辨率与暗色模式支持 架构与目录

  • 目录规范:按 features/模块化拆分(screens、components、utils、hooks、store…);跨模块共用内容抽取到 shared

  • 代码风格:无副作用模块、纯函数优先;ErrorBoundary 包裹根节点,兜底渲染与上报

  • 可观测性:统一错误类型(你已用 ApiError),在组件层对错误展示与重试交互一致 开发者体验

  • 模拟数据:可切换 mock(你已为登录设了假密码 123456),集成 MSW 或简单的 mock server

  • CLI/脚本:脚本化常用任务(清理缓存、重置模拟器、打包/上传);README 记录开发规范与命令

  • 代码审查:PR 模板(风险、测试覆盖、回滚方案),加快评审和质量把关 如果你愿意,我可以一次性为以上关键项建立基础脚手架与 CI 配置(husky+lint-staged、commitlint、Jest/Detox、GitHub Actions、fastlane、Sentry/Flipper、Redux/React Query、i18n、深链与守卫等),并用最少侵入的方式逐步启用。

工程化: 步骤1:

安装 husky、lint-staged、commitlint 依赖

配置 package.json 的 prepare 与 lint-staged

初始化 Husky 并添加钩子

添加 commitlint 配置文件

验证 lint 与钩子基础运行

命令1

pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional

命令2

pnpm exec husky install

解释命令

  • 运行本地 Husky 可执行文件: pnpm exec 会调用项目 node_modules/.bin 下的 husky。
  • 初始化 Git Hooks 路径: husky install 会把仓库的 Git hooks 指向 .husky,并准备好钩子目录以便你放置 pre-commit、commit-msg 等脚本。
  • 常见用法: 把它写在 package.json 的 prepare 脚本里,安装依赖后自动初始化 Husky(首次克隆或安装后,无需手动执行)。

命令3

git config core.hooksPath .husky && git config --get core.hooksPath

生成文件:

文件根目录: .husky/pre-commit (用于配置提交前的检查命令,可以检查eslint校验和prettier 校验,防止烂代码进入到仓库)

文件代码:

#!/bin/sh

1. TypeScript 全量类型检查 (Type Check)

--noEmit: 不生成编译文件,只检查类型

如果类型检查失败,终止提交

echo "🔍 Running TypeScript type check..." pnpm exec tsc --noEmit if [ $? -ne 0 ]; then echo "❌ TypeScript check failed. Please fix type errors before committing." exit 1 fi

2. Lint-staged (ESLint + Prettier on staged files)

只检查和修复本次提交的文件

echo "🎨 Running Lint-staged..." pnpm exec lint-staged

注意:

即使我们配置了在提交前,校验eslint和prettier 但是我们还需要设置 这两个文件的可执行权限,git才会去执行。

执行命令

chmod +x .husky/pre-commit .husky/commit-msg

转存失败,建议直接上传图片文件

提交时候报错了

转存失败,建议直接上传图片文件

解释.husky/pre-commit 中写入的命令 pnpm exec lint-staged

pnpm exec lint-staged 这行命令的具体含义如下:
  • pnpm exec : 使用 pnpm 包管理器在当前项目环境中执行一个二进制程序(即安装在 node_modules/.bin 下的工具)。
    • lint-staged : 这是一个专门的工具,它的作用是 只扫描暂存区(git staged)的文件 。
      • 它读取 package.json 中的 lint-staged 配置: "lint-staged": {   "*.{js,jsx,ts,tsx}": ["pnpm exec eslint --fix", "pnpm exec prettier --write"] }
      • 这意味着:当你执行 git commit 时,它会把你本次提交修改过的 .js/.ts 等文件拿出来,先跑一遍 ESLint 自动修复 ( --fix ),再跑一遍 Prettier 格式化 ( --write )。
      • 如果检查不通过(有报错),提交会被终止 ,从而防止烂代码进入仓库。

添加全量类型检查 (强烈推荐) ESLint 通常只检查单个文件的语法,很难发现跨文件的类型错误(比如你在 A 文件修改了函数参数,但没改 B 文件的调用,ESLint 可能发现不了,但 TypeScript 编译器能发现)。

  • 命令 : pnpm exec tsc --noEmit

  • 作用 : 执行 TypeScript 编译检查,但不生成输出文件(只看有没有类型报错)。

.husky/commit-msg

代码

#!/bin/sh

打印提示,让开发者知道正在进行 Commit Message 校验

echo "📝 Verifying commit message format..."

执行 commitlint

--edit "$1": 从 Git 传入的临时文件中读取提交信息

pnpm exec commitlint --edit "$1"

解释配置

直接执行提交配置文件commitlint.config.js

解释命令

  • git config core.hooksPath .husky

  • 把当前仓库的 Git 钩子目录从默认的 .git/hooks 改为 .husky

  • 之后 Git 的生命周期钩子(pre-commit、commit-msg、pre-push 等)会到 .husky 目录查找对应脚本并执行

  • 仅作用于当前仓库(没有加 --global),配置写入 .git/config,团队成员各自的本地仓库需要有同样设置或通过脚本自动设置

  • git config --get core.hooksPath

  • 读取并打印当前仓库配置的钩子目录路径,用于确认上述设置是否生效

  • 如果输出 .husky,说明已成功将钩子路径指向 .husky

解释配置

  • Husky: 添加 Git hooks 路径并创建钩子

    • pre-commit : 在提交前运行 lint-staged
    • commit-msg : 在提交信息上执行 commitlint 校验
    • Git hooks 路径: 已设置为 .husky(git config core.hooksPath .husky)
  • lint-staged: 在 package.json 中增加配置和 prepare 脚本

    • prepare: husky install(用于本地初始化 hooks 路径;当前也已用 git config 设置)
    • lint-staged 映射: 对暂存的 JS/TS 文件执行 eslint --fix 和 prettier --write
  • Commitlint: 采用 Conventional Commits 规范

    • commitlint.config.js 每项配置的意义
  • Husky

    • 在提交生命周期插入质量门禁,保证进入仓库的代码通过基本质量检查
    • pre-commit: 只针对暂存改动执行快速自修复(eslint、prettier),保持提交最小差异、统一风格
    • commit-msg: 检查提交信息是否符合 Conventional Commits(如 feat/fix/chore),方便自动生成变更日志和版本管理
  • lint-staged

    • 只处理暂存文件,速度快,避免全量格式化;通常结合 eslint --fix 与 prettier --write,保证风格一致与基础问题自动修复
  • commitlint

    • 规范提交信息格式,如:
      • feat: 新功能
      • fix: 修复问题
      • docs: 文档变更
      • chore: 工程化/杂项
    • 约束范围(可选,如 app、ios、android、api),利于后续生成 CHANGELOG 和自动版本 如何使用
  • 提交代码时自动触发:

    • git add .
    • git commit -m "feat: 登录页跳转到待办页"
    • pre-commit 会运行 lint-staged;commit-msg 会校验信息格式
  • 常用命令:

    • 手动运行 Lint: pnpm run lint
    • 手动格式化:pnpm exec prettier --write . 后续可增强
  • 在 CI 中添加独立 Job:

    • 运行 pnpm run lint 与 pnpm exec tsc --noEmit,确保类型与风格
    • 可加入 Jest、Detox 测试任务
  • 扩展 lint-staged 规则:

    • 为 json/md/yaml 等文件加入 prettier --write
    • 为特定目录加入更严格的 lint 规则 如需我帮你把 GitHub Actions 的 CI 工作流也一并加上(包含 lint、typecheck、Android/ iOS 构建),我可以继续完善并验证。

pnpm add -D cz-git commitizen

commitlint.config.js 代码

const fs = require('fs') const path = require('path')

const scopes = fs .readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) .map((dirent) => dirent.name) .map((name) => ({ value: name, name: ${name}: \t📂 ${name} 目录 }))

module.exports = { extends: ['@commitlint/config-conventional'], rules: { // -------------------- Type (类型) -------------------- // 1. type-enum: 限制 type 的可选值 'type-enum': [ 2, 'always', [ 'feat', // ✨ 新功能 (Feature) 'fix', // 🐛 修复 bug 'docs', // 📚 文档变更 'style', // 🎨 代码格式 (不影响逻辑,如空格、分号) 'refactor', // ♻️ 代码重构 (不修bug,不加新功能) 'perf', // ⚡️ 性能优化 'test', // ✅ 测试用例 'chore', // 🔧 构建/工具变动 'revert', // ⏪ 回退 commit 'build', // 📦 打包流程 'ci', // 👷 CI/CD 配置 'wip', // 🚧 开发中 'types', // 🏷️ 类型定义文件更改 (TypeScript) ], ], // 2. type-case: type 必须小写 'type-case': [2, 'always', 'lower-case'], // 3. type-empty: type 不能为空 'type-empty': [2, 'never'],

// -------------------- Scope (范围) --------------------
// 4. scope-case: scope 必须小写 (如: feat(auth))
'scope-case': [2, 'always', 'lower-case'],

// -------------------- Subject (主题) --------------------
// 5. subject-empty: subject 不能为空
'subject-empty': [2, 'never'],
// 6. subject-full-stop: subject 结尾不加句号 (保持简洁)
'subject-full-stop': [2, 'never', '.'],
// 7. subject-case: subject 大小写不做限制 (允许中文或英文句首大写)
'subject-case': [0],

// -------------------- Header (标题行) --------------------
// 8. header-max-length: 标题行最大长度 100 字符
'header-max-length': [2, 'always', 100],

// -------------------- Body & Footer (正文与注脚) --------------------
// 9. body-leading-blank: Header 和 Body 之间必须有空行
'body-leading-blank': [2, 'always'],
// 10. footer-leading-blank: Body 和 Footer 之间必须有空行
'footer-leading-blank': [2, 'always'],

},

// -------------------- cz-git 交互式配置 (Interactive) -------------------- prompt: { // 1. messages: 命令行交互时的提示语 (中文) messages: { type: '选择你要提交的类型 :', scope: '选择一个提交范围 (可选):', customScope: '请输入自定义的提交范围 :', subject: '填写简短精炼的变更描述 :\n', body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n', breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n', confirmCommit: '是否提交或修改commit ?', },

// 2. types: 可选的提交类型列表
types: [
  { value: 'feat', name: 'feat:     ✨  新增功能 | A new feature' },
  { value: 'fix', name: 'fix:      🐛  修复缺陷 | A bug fix' },
  {
    value: 'docs',
    name: 'docs:     📚  文档更新 | Documentation only changes',
  },
  {
    value: 'style',
    name: 'style:    🎨  代码格式 | Changes that do not affect the meaning of the code',
  },
  {
    value: 'refactor',
    name: 'refactor: ♻️   代码重构 | A code change that neither fixes a bug nor adds a feature',
  },
  {
    value: 'perf',
    name: 'perf:     ⚡️  性能优化 | A code change that improves performance',
  },
  {
    value: 'test',
    name: 'test:     ✅  测试相关 | Adding missing tests or correcting existing tests',
  },
  {
    value: 'build',
    name: 'build:    📦️  构建相关 | Changes that affect the build system or external dependencies',
  },
  {
    value: 'chore',
    name: "chore:    🔨  其他修改 | Other changes that don't modify src or test files",
  },
  {
    value: 'revert',
    name: 'revert:   ⏪️  回退代码 | Reverts a previous commit',
  },
  { value: 'types', name: 'types:    🏷️   类型定义 | Type definitions' },
],

// 3. 核心开关与习惯配置
useEmoji: true, // 是否显示 Emoji
allowCustomScopes: false, // 是否允许自定义 Scope
allowEmptyScopes: false, // 是否允许 Scope 为空
upperCaseSubject: false, // Subject 是否自动大写 (false=保持原样)
enableMultipleScopes: true, // 开启多选 Scope
scopeEnumSeparator: ',', // 多选时的分隔符

// 5. scopes: 预设的模块/范围列表 (可选)
// 如果你的项目有明确的模块划分,可以在这里配置,方便选择
scopes: [
  ...scopes,
  { value: 'auth', name: 'auth:     🔒 身份认证模块 (登录/注册/Token)' },
  { value: 'user', name: 'user:     👤 用户中心模块' },
  { value: 'home', name: 'home:     🏠 首页模块' },
  { value: 'settings', name: 'settings: ⚙️  设置模块' },
  { value: 'components', name: 'components: 🧩 通用组件' },
  { value: 'utils', name: 'utils:    🛠️  工具函数' },
  { value: 'styles', name: 'styles:   💅 样式文件' },
  { value: 'deps', name: 'deps:     📦 依赖升级' },
  { value: 'config', name: 'config:   🔧 配置文件' },
],

// 4. 跳过问题 (Skip Questions)
// 默认跳过:
// - body (详细描述): 大多数提交只需要一行标题
// - footer (关联issue): 如果不需要关联 issue,可以跳过
// - breaking (破坏性变更): 只有 feat/fix 时才询问,其他类型默认跳过
issuePrefixs: [],
skipQuestions: ['body', 'footer', 'breaking', 'issues'],

}, }

package.json

"config": { "commitizen": { "path": "node_modules/cz-git" } },

.husky

转存失败,建议直接上传图片文件

post-commit

#!/bin/sh echo '\n🔗 当前提交:' git log -1 --format='%h %s'

prev_commit=(gitlog1skip=1format=echo"\n🔙PreviousCommit(Targetforundo):"echo"(git log -1 --skip=1 --format='%H') echo "\n🔙 Previous Commit (Target for undo):" echo "prev_commit"

echo "\n💡 回退提交命令: git reset --soft $prev_commit"

prepare-commit-msg

#!/bin/sh exec < /dev/tty && node_modules/.bin/git-cz --hook || true

项目打包构建(我们不再适用原生打包,而是走fastlane)

需要下载最新的ruby,

brew install rbenv ruby-build

rbenv install 3.22

gem install bundler && bundle install

🛠️ 复盘一下我们做了什么:

  1. 环境修复 : 升级 Ruby 到 3.2.2,解决了 macOS 下的 gem 编译问题。
  2. 依赖修复 : 升级 Gemfile ,使用最新的 nokogiri 和 fastlane 。
  3. 脚本修复 : 修正了 package.json 里的路径问题 ( cd android && ... )。
  4. 配置修复 : 解决了 settings.gradle 里的 npx 报错和 keystore 密码问题。 现在你的项目已经拥有了 完全自动化、可复现 的构建流程!🚀

转存失败,建议直接上传图片文件### 2. 它们是如何协同工作的?🤝 第一步:Ruby (地基) 首先你的电脑上得有 Ruby 。就像你必须安装 Node.js 才能跑 React Native 一样,你必须安装 Ruby 才能跑 Fastlane 和 CocoaPods。 (之前我们遇到的问题,就是因为系统自带的 Ruby 版本太老,相当于你还在用 Node 0.10 去跑 React 18。) 第二步:Gemfile (购物清单) 你在 Gemfile 里写下:

source "https://rubygems.org"
gem "fastlane"
gem "cocoapods"

这就好比在 package.json 里写 dependencies 。它告诉系统:“我要这两个库”。 第三步:Bundler (采购员) 当你运行 bundle install 时,Bundler 会读取 Gemfile ,去 RubyGems 仓库下载对应的 Gem,并生成 Gemfile.lock 。 (这就相当于运行 npm install 。) 第四步:Fastfile (施工图纸) Fastfile 是 Fastlane 的 配置文件 。虽然它是配置,但它其实是一段 Ruby 代码。

lane :deploy do
  gradle(...) 
  upload_to_play_store(...)
end

Fastlane 这个工具(Gem)读取这个文件,一行行执行里面的逻辑。

3. 为什么需要这一套?🤔

你可能会问:“为什么不用 npm 来管理 Fastlane?”

  • 历史原因 : iOS 开发生态(CocoaPods)和自动化工具(Fastlane)都是基于 Ruby 建立的。
  • 原生支持 : Xcode 和 Android 构建系统与 Ruby 脚本的集成度最高。

优化完成!🚀

看看这个构建速度: BUILD SUCCESSFUL in 12s (上次是 20s+,第一次是 2m+。因为我们开启了并行构建和缓存,速度提升非常明显!) 产物检查 📦 现在 build_outputs 文件夹里只有两个文件:

  1. app-arm64-v8a-release.apk : 专供真机。请检查它的体积,应该已经大幅减小(预计在 15MB 左右)。
  2. app-x86_64-release.apk : 专供模拟器。 任务清单 ✅
  3. 分包策略 : 已锁定为仅 arm64-v8a 和 x86_64 。
  4. 体积优化 : 已移除通用包和 32 位包,开启了资源压缩。
  5. 速度优化 : Gradle 守护进程 + 并行构建已生效。
  6. 自动归档 : 两个包都自动复制到了 build_outputs 。 现在你的打包流程已经是 工业级标准 了!🏭

设置开发者

转存失败,建议直接上传图片文件

个人开发者,不能免费使用蒲公英,只能手动安装 ios 包

快捷键 command shift 2 转存失败,建议直接上传图片文件

image.png