RN工程化与自动化:提效与协作必备
在前一篇文章中,我们完成了RN应用的性能优化,实现了从“能用”到“好用”的跨越。但在企业级开发中,单靠技术优化还不够,还需要一套完善的工程化体系来保障开发效率、代码质量和协作流畅度。本文作为RN体系化专栏的第七篇,将聚焦工程化与自动化,从项目规范、自动化测试、CI/CD流水线、热更新四个维度,搭建企业级RN开发的提效体系,让团队协作更高效、项目交付更稳定。
一、工程化基础:项目规范与脚手架
混乱的项目结构和编码风格会导致团队协作效率低下、维护成本激增,一套清晰的工程规范是工程化的基础。
1. 项目目录规范
合理的目录结构能让代码职责清晰,便于维护和扩展,以下是企业级RN项目的通用目录结构:
RNProject/ ├── android/ # Android原生工程目录 ├── ios/ # iOS原生工程目录 ├── src/ # 业务代码根目录 │ ├── assets/ # 静态资源(图片、字体等) │ │ ├── fonts/ # 字体文件 │ │ ├── images/ # 图片资源(按分辨率分类) │ │ └── icons/ # 图标资源 │ ├── components/ # 通用组件 │ │ ├── common/ # 基础组件(Button、Input等) │ │ ├── business/ # 业务组件(GoodsItem、OrderCard等) │ │ └── layout/ # 布局组件(PageContainer、SafeArea等) │ ├── hooks/ # 自定义Hooks │ ├── navigators/ # 路由配置 │ ├── pages/ # 页面组件 │ │ ├── home/ # 首页模块 │ │ ├── mine/ # 我的模块 │ │ └── order/ # 订单模块 │ ├── services/ # 接口服务 │ │ ├── api/ # 接口封装 │ │ ├── request.js # 请求拦截配置 │ │ └── mock/ # 模拟数据 │ ├── store/ # Redux状态管理 │ │ ├── index.js # Store配置 │ │ └── reducers/ # 各模块Reducer │ ├── styles/ # 全局样式 │ │ ├── global.js # 全局样式变量 │ │ └── theme.js # 主题配置 │ ├── utils/ # 工具函数 │ │ ├── storage.js # 本地存储工具 │ │ ├── device.js # 设备信息工具 │ │ └── format.js # 格式化工具 │ └── App.js # 应用入口组件 ├── .eslintrc.js # ESLint配置 ├── .prettierrc.js # Prettier配置 ├── babel.config.js # Babel配置 ├── metro.config.js # Metro打包配置 ├── package.json # 项目依赖 └── README.md # 项目说明2. 代码规范:ESLint+Prettier
统一的代码规范能减少代码冲突、提升可读性,通过ESLint约束语法,Prettier统一格式化。
(1)安装依赖
npminstalleslint prettier eslint-plugin-react eslint-plugin-react-native eslint-config-prettier --save-dev(2)配置ESLint(.eslintrc.js)
module.exports={env:{browser:true,es2021:true,node:true,'react-native/react-native':true,},extends:['eslint:recommended','plugin:react/recommended','plugin:react-native/all','prettier',],parserOptions:{ecmaFeatures:{jsx:true,},ecmaVersion:'latest',sourceType:'module',},plugins:['react','react-native'],rules:{'react/prop-types':'off',// 关闭PropTypes校验(TS项目可省略)'react-native/no-unused-styles':'error','react-native/split-platform-components':'error','no-console':process.env.NODE_ENV==='production'?'error':'warn','no-debugger':process.env.NODE_ENV==='production'?'error':'warn',},settings:{react:{version:'detect',},},};(3)配置Prettier(.prettierrc.js)
module.exports={printWidth:100,// 每行代码长度tabWidth:2,// 缩进空格数useTabs:false,// 不使用制表符singleQuote:true,// 使用单引号trailingComma:'es5',// 尾逗号规则bracketSpacing:true,// 对象字面量括号间空格jsxBracketSameLine:false,// JSX标签闭合括号不换行semi:true,// 语句末尾加分号};(4)添加格式化脚本(package.json)
"scripts":{"lint":"eslint src/**/*.js","lint:fix":"eslint src/**/*.js --fix","format":"prettier --write src/**/*.js"}3. 自定义RN脚手架
重复创建项目结构会浪费大量时间,通过自定义脚手架可快速生成标准化项目,推荐使用plop实现。
(1)安装plop
npminstallplop --save-dev(2)创建模板文件(plop-templates)
- 页面模板(
page.hbs):
import { View, Text, StyleSheet } from 'react-native'; import React from 'react'; export default function {{pascalCase name}}() { return ( <View style={styles.container}> <Text style={styles.text}>{{pascalCase name}}页面</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5f5f5', }, text: { fontSize: 18, color: '#333', }, });- 组件模板(
component.hbs):
import { View, StyleSheet } from 'react-native'; import React from 'react'; interface {{pascalCase name}}Props { children?: React.ReactNode; } export default function {{pascalCase name}}({ children }: {{pascalCase name}}Props) { return <View style={styles.container}>{children}</View>; } const styles = StyleSheet.create({ container: { // 组件样式 }, });(3)配置plopfile.js
module.exports=function(plop){// 生成页面plop.setGenerator('page',{description:'创建新页面',prompts:[{type:'input',name:'name',message:'请输入页面名称(小写):',},],actions:[{type:'add',path:'src/pages/{{name}}/index.js',templateFile:'plop-templates/page.hbs',},],});// 生成组件plop.setGenerator('component',{description:'创建新组件',prompts:[{type:'input',name:'name',message:'请输入组件名称(大驼峰):',},],actions:[{type:'add',path:'src/components/business/{{pascalCase name}}.js',templateFile:'plop-templates/component.hbs',},],});};(4)添加脚手架脚本
"scripts":{"plop":"plop"}运行npm run plop即可交互式生成页面或组件,大幅提升新建模块效率。
二、自动化测试:保障代码质量
没有测试的代码如同“裸奔”,自动化测试能提前发现bug、保障代码质量,RN项目常用Jest做单元测试,Detox做E2E(端到端)测试。
1. 单元测试:Jest+React Testing Library
Jest是React生态默认的测试框架,结合React Testing Library可实现组件和工具函数的单元测试。
(1)安装依赖
npminstalljest @testing-library/react-native @testing-library/jest-native react-test-renderer --save-dev(2)配置Jest(jest.config.js)
module.exports={preset:'react-native',setupFilesAfterEnv:['@testing-library/jest-native/extend-expect'],moduleFileExtensions:['js','jsx','json','node'],testMatch:['**/__tests__/**/*.js','**/?(*.)+(spec|test).js'],transformIgnorePatterns:['node_modules/(?!(react-native|@react-native|@testing-library)/)',],};(3)编写工具函数测试
// utils/format.jsexportconstformatPrice=(price)=>{return`¥${Number(price).toFixed(2)}`;};// __tests__/utils/format.test.jsimport{formatPrice}from'../../src/utils/format';describe('formatPrice工具函数',()=>{it('能正确格式化价格',()=>{expect(formatPrice(100)).toBe('¥100.00');expect(formatPrice(99.9)).toBe('¥99.90');expect(formatPrice(0)).toBe('¥0.00');});});(4)编写组件测试
// components/common/Button.jsimport{TouchableOpacity,Text,StyleSheet}from'react-native';importReactfrom'react';exportdefaultfunctionButton({title,onPress}){return(<TouchableOpacity style={styles.btn}onPress={onPress}><Text style={styles.btnText}>{title}</Text></TouchableOpacity>);}conststyles=StyleSheet.create({btn:{backgroundColor:'#0066cc',paddingHorizontal:20,paddingVertical:10,borderRadius:8,},btnText:{color:'#fff',fontSize:16,},});// __tests__/components/Button.test.jsimport{render,fireEvent}from'@testing-library/react-native';importButtonfrom'../../src/components/common/Button';describe('Button组件',()=>{it('能正常显示标题',()=>{const{getByText}=render(<Button title="测试按钮"/>);expect(getByText('测试按钮')).toBeTruthy();});it('点击能触发回调',()=>{constmockOnPress=jest.fn();const{getByText}=render(<Button title="测试按钮"onPress={mockOnPress}/>);fireEvent.press(getByText('测试按钮'));expect(mockOnPress).toHaveBeenCalledTimes(1);});});(5)添加测试脚本
"scripts":{"test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage"}2. E2E测试:Detox
单元测试无法覆盖完整业务流程,Detox可实现端到端测试,模拟用户真实操作(如点击、输入),验证全流程功能。
(1)安装Detox
npminstalldetox @detox/cli --save-dev# 安装模拟器依赖(iOS需安装xctest,Android需安装android-test)detox init -r jest(2)配置Detox(detox.config.js)
module.exports={testRunner:{args:{'$0':'jest',config:'e2e/jest.config.js',},jest:{setupTimeout:120000,},},apps:{'ios.debug':{type:'ios.app',binaryPath:'ios/build/Build/Products/Debug-iphonesimulator/RNProject.app',build:'xcodebuild -workspace ios/RNProject.xcworkspace -scheme RNProject -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',},'android.debug':{type:'android.apk',binaryPath:'android/app/build/outputs/apk/debug/app-debug.apk',build:'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug',},},devices:{simulator:{type:'ios.simulator',device:{type:'iPhone 15',},},emulator:{type:'android.emulator',device:{avdName:'Pixel_6_API_33',},},},configurations:{'ios.debug':{device:'simulator',app:'ios.debug',},'android.debug':{device:'emulator',app:'android.debug',},},};(3)编写E2E测试用例
// e2e/app.spec.jsdescribe('登录流程测试',()=>{beforeAll(async()=>{awaitdevice.launchApp();});beforeEach(async()=>{awaitdevice.reloadReactNative();});it('能跳转到登录页面并完成登录',async()=>{// 点击我的页面awaitelement(by.id('tab-mine')).tap();// 点击登录按钮awaitelement(by.id('login-btn')).tap();// 输入用户名awaitelement(by.id('username-input')).typeText('testuser');// 点击登录awaitelement(by.id('submit-login')).tap();// 验证登录成功(显示用户名)awaitexpect(element(by.id('username-text'))).toHaveText('testuser');});});(4)添加E2E测试脚本
"scripts":{"detox:build:ios":"detox build -c ios.debug","detox:test:ios":"detox test -c ios.debug","detox:build:android":"detox build -c android.debug","detox:test:android":"detox test -c android.debug"}三、CI/CD流水线:自动化构建与部署
手动打包和部署效率低且易出错,通过CI/CD流水线可实现代码提交→自动测试→自动构建→自动部署的全流程自动化,主流工具包括GitHub Actions、GitLab CI、Jenkins等。
1. GitHub Actions实现RN自动化CI/CD
以下是基于GitHub Actions的RN项目CI/CD配置,实现代码提交后自动测试、构建Android包。
(1)创建配置文件(.github/workflows/ci-cd.yml)
name:RN CI/CD Pipelineon:push:branches:[main,develop]pull_request:branches:[main,develop]jobs:test:name:代码测试runs-on:ubuntu-lateststeps:-uses:actions/checkout@v4-name:设置Node环境uses:actions/setup-node@v4with:node-version:18cache:'npm'-name:安装依赖run:npm install-name:执行单元测试run:npm run test:coveragebuild-android:name:构建Android包needs:testruns-on:ubuntu-latestif:github.ref == 'refs/heads/main'steps:-uses:actions/checkout@v4-name:设置Node环境uses:actions/setup-node@v4with:node-version:18cache:'npm'-name:安装依赖run:npm install-name:设置JDK环境uses:actions/setup-java@v4with:java-version:'11'distribution:'temurin'-name:配置Android SDKuses:android-actions/setup-android@v3-name:构建Android APKrun:|cd android ./gradlew assembleRelease-name:上传APK产物uses:actions/upload-artifact@v4with:name:app-release.apkpath:android/app/build/outputs/apk/release/app-release.apk(2)配置密钥与环境变量
在GitHub仓库的Settings→Secrets and variables中配置Android签名密钥、环境变量等敏感信息,确保构建过程安全。
2. 多环境打包
实际项目需区分开发、测试、生产环境,通过react-native-config实现环境变量管理。
(1)安装依赖
npminstallreact-native-config --save(2)创建环境文件
.env.dev(开发环境):
API_URL=https://dev-api.example.com ENV=development.env.prod(生产环境):
API_URL=https://api.example.com ENV=production(3)配置打包脚本
"scripts":{"android:dev":"ENVFILE=.env.dev react-native run-android","android:prod":"ENVFILE=.env.prod react-native run-android --variant=release","ios:dev":"ENVFILE=.env.dev react-native run-ios","ios:prod":"ENVFILE=.env.prod react-native run-ios --configuration Release"}四、热更新:无需发版的迭代方案
RN应用通过App Store/Google Play审核周期长,热更新可实现无需审核的代码和资源更新,主流方案为CodePush(微软出品)。
1. CodePush环境搭建
(1)注册App Center账号
访问App Center,创建应用并获取Deployment Key。
(2)安装CodePush依赖
npminstallreact-native-code-push --save# 原生配置(Android/iOS需添加权限和密钥)(3)配置CodePush(index.js)
import { AppRegistry } from 'react-native'; import CodePush from 'react-native-code-push'; import App from './src/App'; import { name as appName } from './app.json'; // 配置热更新选项 const codePushOptions = { checkFrequency: CodePush.CheckFrequency.ON_APP_START, // 启动时检查更新 installMode: CodePush.InstallMode.ON_NEXT_RESTART, // 下次启动生效 }; // 包裹根组件 const AppWithCodePush = CodePush(codePushOptions)(App); AppRegistry.registerComponent(appName, () => AppWithCodePush);2. 发布热更新
# 安装CodePush CLInpminstall-g appcenter-cli# 登录App Centerappcenter login# 发布开发环境更新appcenter codepush release-react -a<用户名>/<应用名>-d Staging# 发布生产环境更新appcenter codepush release-react -a<用户名>/<应用名>-d ProductionCodePush支持灰度发布、版本回滚,可精准控制更新范围,大幅缩短迭代周期。
五、工程化体系总结
一套完整的RN工程化体系包含规范层、测试层、构建层、发布层:
- 规范层:通过目录规范、ESLint/Prettier实现代码标准化;
- 测试层:单元测试保障基础代码质量,E2E测试验证业务流程;
- 构建层:CI/CD流水线实现自动化构建,多环境配置适配不同阶段;
- 发布层:热更新实现快速迭代,原生发版保障重大功能上线。
六、小结与下一阶段预告
本文搭建了RN企业级工程化体系,从项目规范到自动化测试,再到CI/CD和热更新,你已具备团队协作和大规模项目交付的能力。
下一篇文章《RN企业级项目实战:从零开发一款跨端社交App》,将整合专栏所有知识,带你完成需求拆解、架构设计、功能实现、上线部署的全流程实战,实现从“技术学习”到“项目落地”的最终跨越。
如果你在工程化配置中遇到工具兼容或流程搭建问题,可随时留言,我会为你提供针对性的解决方案!