打开大多数开发者的移动端项目,根目录下总躺着几个熟悉的文件夹:app、components、screens、hooks、utils。起初,这四五个抽屉足够清爽,但当产品从简单的原型变成撑起百万帖子的Instagram、承载数十亿条消息的WhatsApp、需要实时位置刷新的Uber、或管理海量影视内容的Netflix时,那个平坦的文件格立刻开始崩裂。

文件互相遮眼,功能缠成死结,导航逻辑散落四方,每次同步都像推开一扇吱嘎作响的老门,新人入职第一个月几乎全在找代码。

打开网易新闻 查看精彩图片

真正的挑战不是“再写一个屏幕”,而是一个能够扛住数年迭代、容纳数十位工程师并肩作战的代码骨架。面对这种量级,小应用的惯性思维——按文件类型分堆——会迅速失效。一个components文件夹下堆积着PostCard、UserAvatar、RideCard、PaymentCard、MessageBubble、VideoPlayer,几百个组件像被随意塞入抽屉的零件,找到和改动一处逻辑的成本直线飙升。生产环境的真实需求,倒逼我们转向另一种组织逻辑:按业务特性切分,像大公司那样把Feed、聊天、个人主页、支付、通知、认证看作独立的功能板块,而不是零散的按钮和屏。

这种从“文件类型”到“业务特征”的迁移,是规模化移动应用架构的第一块基石。好的架构提供五个维度的支撑:可扩展——新功能像插件一样独立生长;可维护——每个工程师清楚代码的归属地;团队协作——多人可以同时在不同特性上工作而不冲撞;性能——复杂度增长时系统依旧顺滑;开发者体验——每天打开项目都保持可预测的节奏。Expo Router的出现,恰好为React Native的导航机制提供了一个与文件系统天然耦合的方案,让这种特征切片变得容易落地。

传统React Navigation需要手动堆叠导航树:在JSX里一层套一层Screen,项目变大时,导航配置本身就成了一株很难修剪的藤蔓。Expo Router将路由约定化到文件系统上:文件夹即路由段,文件名映射到屏幕,这使得代码结构既是导航图,又是业务疆域图。一个面向千万用户规模的生产级结构,由此可以自然形成两层分区:app/目录下用(public)和(protected)做页面分组,再用(tabs)拆分主页tab;而真正的业务逻辑、UI组件、网络请求、工具函数,则被整体移入features/和shared/两大区。

分开看,features/之下就是一个个独立王国:auth掌管登录注册的所有组件、hooks、API调用;feed包含内容流的排序算法、帖子卡片、刷新逻辑;chat收纳消息气泡、发送状态、实时推送处理;profile捆绑用户主页、编辑资料、收藏夹;notifications整合推送策略、通知列表、角标管理;payments集中支付方式、交易记录和安全校验。每个功能块内部可以继续细分子目录,但关键边界是——一个功能块的改动不会让另一个功能块闻到焦味。shared/区则是通用零件库:共享的基础组件、通用hook、基础库和工具函数,保证复用而不绑死在任何业务上。

这种分离并非为了美观。当Chat团队想要把WebSocket通道从原生Socket库迁移到自定义协议时,他们只需要在features/chat/内修一条新路,feed团队的同事甚至不会在合并代码时遇到一次冲突。当通知系统需要接入新的第三方推送SDK时,features/notifications/的改动只局限在自己的城墙内。Expo Router给每个feature一个清晰的路由锚点,file-system based routing让新建一个聊天列表页就是新建一个chat/rooms.tsx文件,不需要去导航配置中心挂号——文件在哪,路径就在哪,即时增加、移动或删除,团队几乎不用为导航架构开额外会议。

初创团队常常担心过早架构会拖慢节奏,但当应用从开发者自己的手机,跑到百万甚至亿级用户的设备上时,文件夹结构的疲劳周期远比想象中来得更早。先搭建一个app/(public)/login.tsx、app/(protected)/(tabs)/home.tsx和features/的骨架,并不会比平铺直叙的screens/多写几行,但它预留了生长的褶皱。当Instagram级的内容流涌入时,feed模块可以在自己的features/feed里藏起十余个组件、三个数据缓存层、两套瀑布流算法,apps目录只留一扇干净的路由门;当Whatsapp级的实时消息压过来时,chat的特性层能独自消化消息队列、信道管理和离线补推,而不让主工程卡在一团if/else里。

这套骨架还有另一个隐蔽的收益:onboarding新工程师不再需要在一个巨大无序的文件夹迷宫中迷失数周,而是可以直抵架构明确的功能疆域,快速理解系统并开始贡献。