ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Shopify 弃用 React Native 背后:跨端开发困境与原生回归的技术选型思考

Shopify 弃用 React Native 背后:跨端开发困境与原生回归的技术选型思考 1. 事件回顾Shopify 为什么在 6 年后按下撤回键先说结论2024 年 10 月Shopify 官方工程博客发了一篇文章宣布他们正在逐步放弃 React Native转向 Android 端用 Kotlin、iOS 端用 Swift 的原生技术栈重新构建 Shopify App 和 Shopify POS 等核心移动应用。这条消息在跨端开发圈里炸得挺凶。毕竟 Shopify 不是那种先试个水、不行就撤的小团队——他们在 React Native 上投了整整 6 年旗下不少 App 都是基于 RN 构建的还要维护一个内部组件库和一套针对商家场景的扩展机制。更关键的是Shopify 的移动应用不像普通工具类 App 那样只展示信息流它要面对的是复杂的商家后台、线下 POS 收银、订单库存管理这种重业务场景。整个体系都建立在 RN 之上却要主动拆掉重来这种决断力比当年选错技术栈更值得聊。1.1 Shopify 当年为什么押注 React Native其实不是拍脑袋把时间拨回 2018 年前后。那时候移动端技术选型的核心矛盾很直白iOS 和 Android 两套原生代码成本太高而商家既需要 iOS App又需要 Android App还要覆盖商家管理和顾客购物两类完全不同的使用场景。React Native 当时是市场上生态最成熟、社区最活跃的跨端方案之一再加上 Shopify 本身是一个 Web 技术底蕴非常深厚的团队大量工程师的 JavaScript/React 技能可以直接迁移到移动端学习成本和招聘成本都更低。这个选择在当时没有任何问题。RN 让 Shopify 用一套核心逻辑覆盖双端业务迭代速度肉眼可见地提了上来组件复用也做得有模有样。等到他们后来推出 Shopify POS、Shop 这类 App 时RN 的快速铺量价值依然存在——你不需要为每个新端重新招聘一整支原生团队。所以这事不能简单解读成React Native 不行了。它更像是一个企业在不同阶段做出了符合当时处境的决策然后在体量、业务复杂度、用户预期都发生变化之后重新算了一次账。1.2 压垮骆驼的最后一根稻草到底是什么根据 Shopify 工程团队的披露他们在 RN 使用过程中积累的最大痛点是底层抽象失控。RN 的核心思路是 JavaScript 层编写业务逻辑原生层负责渲染和平台能力两者之间靠 Bridge现在是 Fabric/TurboModule 那套新架构通信。理论上 JavaScript 写一遍两端都能跑但在超大型应用中桥接层的通信开销、内存占用和不可预测的崩溃问题会随业务复杂度线性上升。举一个例子在商家后台的订单列表里如果一次性加载大量行数据同时还要处理图片懒加载、动画、下拉刷新、键盘弹出等交互RN 的 JS 线程和原生线程之间频繁通信很容易出现肉眼可见的掉帧和启动时间变长。这类问题不是某一段代码写得不好而是架构层面固有的成本。Shopify 在官方博客里明确提到他们在启动时间、内存占用、可靠性和开发体验上遇到了天花板而这些指标恰恰是商家工具类 App 的生命线。另外还有维护成本。RN 社区虽然活跃但每次大版本升级都要动桥接层、动原生依赖再加上 Shopify 自己维护了那么多内部库升级 RN 版本变成了一场持续数周甚至数月的工程战役。这种隐性成本在技术选型初期几乎没人会算进去但它会日复一日地消耗团队精力。1.3 Shopify 的回归路径不是推倒重来而是渐进替换这里有个特别重要的细节Shopify 并不是发了个公告然后一夜之间删光所有 RN 代码。他们采用了一张渐进式迁移路线图核心思路是用原生代码逐个替换业务模块迁移优先级按用户量、崩溃率、性能敏感度来排。第一优先级是核心体验链路比如首页、订单列表、商品详情这些用户一打开就会用到的模块。第二优先级才是配置管理、报表这类响应速度要求不那么敏感的模块。每替换一个模块团队会对比迁移前后的启动耗时、页面渲染时间、崩溃率等指标用数据确认收益后再进入下一个模块。为了让原生代码与其他逻辑共存他们也调整了整体架构把移动应用改造成以原生壳为主体各个业务模块通过后端驱动、可独立发布的方案来呈现。这个度把控得很好——既没有陷入必须一次性重写的豪赌也没有因为已经投入 6 年就死扛到底这种橡皮筋式的心态很值得想迁移技术栈的团队学习。2. React Native 的真实瓶颈通用框架解决不了复杂应用的非功能需求说回技术本身。React Native 到今天依然是一个生产力很高的跨端方案我见过不少创业团队用 RN 快速做出双端产品效率和成本都比原生有显著优势。但 Shopify 踩到的坑本质上不是RN 性能差这种简单描黑而是它在超大规模、超高复杂度、超敏感性能指标的场景下暴露了通用框架的通病。2.1 桥接模型与失控的复杂度才是核心矛盾RN 的经典架构中JavaScript 线程负责业务逻辑原生线程负责 UI 渲染和各类系统能力两者靠异步桥接通信。这套模型在中小型应用里表现良好但一旦页面复杂度上去、交互变多、数据量变大就会产生两个问题通信开销呈指数级上升以及由于异步通信带来的不可预测性变强。我看到很多团队在调 RN 性能问题时会下意识地找代码哪里写得慢但实际瓶颈往往在桥接层。比如一个 FlatList 在快速滚动时出现白屏或掉帧可能不是渲染函数的问题而是大量列表项的状态更新在 JS 线程与原生线程之间反复排队。你能做的是用 useMemo、React.memo、getItemLayout 各种优化手段去压但始终绕不开那层翻译成本。后来 RN 推出了新架构用 JSI 替代了异步 Bridge允许 JS 直接持有原生对象引用还把渲染拆成了 Fabric理论上能大幅降低通信开销。但新架构从发布到普及也需要时间对 Shopify 这种体量来说等待生态成熟、再把全部业务适配到新架构的周期还是太长。他们没有义务去当小白鼠放弃 RN 转而回归原生其实是更务实的决定。2.2 生态碎片化的真实代价升级不再是改改配置RN 发展至今中间件、原生模块、UI 库都已经非常丰富但生态的碎片化也带来了巨大的维护负担。第三方原生模块要各自适配 iOS 和 Android还要配合 RN 版本升级不断发布新版本。一旦某个库停止维护团队要么自己接手要么重写一个替代实现。注意这些成本在技术选型的 demo 阶段往往看不出来。你拿着一个 RN 开源项目跑起来三五个页面、一两个第三方模块开发体验非常顺滑。但等到业务规模扩大你可能会同时依赖十几个原生模块每一个都要做版本兼容、崩溃监控、性能优化整个系统会变成一座随时可能塌方的积木塔。我自己的经验是跨端方案的真实开发体验和项目体量高度相关。用一个生活化类比RN 就像预制菜开袋即炒、出餐极快、口味稳定很适合小店快速营业但如果你要开一家日料店需要处理极其精细的食材、控制每一道菜的火候那还是得请专业厨师和定制后厨。Shopify 显然是后者。2.3 通用框架的80/20 陷阱覆盖了 80% 场景但也卡住了 20% 的上限做技术选型时大家都很容易被覆盖率吸引跨端方案能帮你覆盖 80% 的界面和逻辑听起来是不是很划算但麻烦就麻烦在剩下的 20%——那些框架没能帮你抽象好的部分才是真正决定产品质感的部分。以 POS 收银系统为例收银台对响应速度的要求接近零容忍每一笔交易的刷卡、扫码、打印小票都得毫秒级响应。RN 的 JS 逻辑层与国际支付 SDK 的交互、蓝牙打印机指令的传输、系统键盘的弹出控制每一条链路都在跟抽象层较劲。就算最后能调通排查一个诡异 bug 的时间成本也远高于原生实现里直接调用系统 API的简单粗暴。换言之通用框架的价值在于下限高它能让平庸的团队做出合格的产品但如果你要做顶级体验上限反而会被框架本身锁死。Shopify 之所以选择回撤就是因为他们意识到自家应用的上限不应该被框架的天花板绑住。3. 原生开发的不可替代性为什么回到原生不是倒退回到原生这四个字在不少人听来像是技术上的倒退尤其现在各种跨端框架一轮一轮地出现好像原生开发已经变成了老古董。但 Shopify 的案例恰恰说明了一个事实原生开发从来就没有退场过它只是沉默地待在底层等那些尝过跨端甜头的团队在够到天花板之后重新想起来还有这么一条路。3.1 性能只是表象真正的壁垒是可预测性与系统级的掌控力要辨析原生开发的价值不能只聊性能。因为单纯比性能Android 上用 Jetpack Compose 写、iOS 上用 SwiftUI 写对比 RN 在绝大多数页面上并不会产生肉眼可见的差距。真正拉开差距的是可预测性和系统级掌控力。可预测性指的是当出现一个 bug 时你能在多大程度上快速定位根因。原生环境里崩溃日志、内存快照、渲染管线、线程调度都有成熟且统一的工具链你可以直接下钻到系统框架层。而 RN 环境下一个 bug 可能藏在 JS 层、桥接层、原生模块、第三方 SDK 的任意一层你得跨着语言和线程边界去排查这就像在一条三车道上来回变道找堵点费时费力。系统级掌控力则体现在底层能力上。举个具体场景在 iOS 上做 Deep Link 和 Universal Link 协同跳转原生代码可以直接处理 URL 路由、SceneDelegate 和 UIWindow 生命周期而 RN 框架需要靠第三方库封装这套封装在系统升级后如果没跟上就会出现各类诡异现象。天然的平台能力永远是原生最顺手这也是很多大厂逐步回归原生、只在特定业务模块保留跨端方案的底层原因。3.2 从团队架构角度解读 Shopify 的选择研发组织架构也要跟着技术栈走技术选型从来不只是技术问题它还会反过来塑造团队组织架构。当年 Shopify 押注 RN一大优势是能让前端工程师直接参与移动端开发人力池变大了。但 6 年过去随着应用复杂度提升他们发现真正的移动端深度问题——性能优化、底层架构、平台特性——还是需要熟悉原生技术栈的工程师来解决。RN 项目组里前端背景的工程师能写好组件逻辑但遇到iOS 内存警告处理Android 生命周期管理这类问题时往往要额外请教原生工程师而原生工程师如果不懂 RN 内部的桥接机制也很难给出最优方案。最后的结果就是团队里每个人都只掌握一半知识真正的深度问题反而没有人能独立搞定。这种既要又要的组织形态在快速迭代期没问题到了精耕细作的成熟期就成了短板。所以我看到 Shopify 的决定后反而觉得它是一次组织架构的正名——与其让前端工程师辛苦补齐原生知识让原生工程师被迫理解 RN 内核不如回归各自最擅长的领域。移动端本来就是一块专业领域专才的产出质量长期来看一定高于通才在框架上打补丁。3.3 一张表看懂什么项目适合原生什么项目适合 RN虽然 Shopify 回归原生给行业带来了震动但普通中小团队完全没有必要跟风一竿子打死 RN。技术选型的核心永远是匹配自身情况。我根据实际经验整理了一个选型参考表项目特征推荐方案理由强交互、强动画、复杂手势原生或 Flutter渲染性能和平台 API 调用最直接大量调用系统能力蓝牙、NFC、相机、传感器原生系统底层的兼容性和调试便利性最好面向 C 端、重 UI 展示、页面逻辑相对规整RN / Flutter双端复用明显迭代效率高团队以 Web/前端工程师为主无独立原生团队RN技能迁移成本最低起步最快需要长期经营、业务规则深水区原生优先可预测性、稳定性和长线维护更可靠已有原生核心能力的存量 App混合方案RN/Flutter 只承载增量业务保留原生骨架这张表的核心逻辑是跨端方案适合展示型 流程型的应用原生方案适合能力型 重体验的应用。你是在做内容社区、电商前台、企业内部工具用 RN 恰到好处你是做支付、仓储、工业控制这种强业务闭环原生更稳。4. 普通团队怎么抄作业技术选型的三个关键决策点Shopify 的案例表面看是一场大厂回撤但对很多团队来说真正的价值在于它把技术选型里最容易忽略的决策点重新摆上了台面。我这里分享三个这几年做技术决策时反复验证过的关键问题。4.1 问题一你的团队有多少原生深度储备很多团队做技术选型时只看团队当前的技术栈却忽略了一个重要事实随着业务演进你会不可避免地触碰到底层能力。如果你团队里没有懂原生的人哪怕先用 RN 快速上线后面遇到一个平台级的 crash 或性能瓶颈就会陷入无人能解的困境。哪怕不采用原生开发团队里至少要有一个人能读懂原生代码、能定位到底层问题。否则我不建议在一个重业务项目上完全押注跨端框架。4.2 问题二你的应用会不会进入非功能需求敏感期如果你做的是一个活动报名页这种轻量应用启动时间多 200 毫秒内存多 20MB用户根本感知不到但如果你做的是商家端、收银端、协同办公这类工具用户每天高频使用、每次卡顿都会直接影响工作效率和口碑。这时候你就必须提前想清楚功能跑通之后性能、启动时间、内存、稳定性这些非功能需求谁来负责跨端框架能让你拥有 80 分的体验但要提到 90 分以上每一分都要付出比原生开发更大的代价。对高频工具类产品选型之初就该把预算倾斜给原生。4.3 问题三你愿意为快速上线付出多少长期成本RN 的最大优势是起步快这是它的核心价值不需要被否定。但技术人往往容易高估起步快的价值低估长期维护的成本。RN 版本升级、第三方库维护、桥接层的持续调试这些长期成本会持续消耗团队资源和程序员心情。我的建议是如果你做的是验证型产品、活动型项目、生命周期短的工具放心用 RN如果你做的是计划长期经营、要持续迭代 3 年以上的产品宁可前期多花一倍时间做原生也不要后期无数次被迫返工。4.4 混合开发是更多团队的现实解还有一个更务实的方案是混合架构以原生为主干保留独立原生团队负责核心模块将一些次要的、对性能不敏感的页面比如帮助中心、富文本内容展示、运营活动页用 RN 或 Flutter 承载。这样既保留了原生在核心链路上的稳定性和可预测性也保留了跨端方案在海量运营页上的迭代速度。Shopify 的迁移路线其实也印证了这个思路他们不会删除所有 RN 代码而是优先替换性能敏感的关键链路保留相对简单的业务模块。这给普通团队最大的启示是技术选型不是一次选定终身你可以把应用拆分出多条赛道让不同框架跑在各自最擅长的路径上。5. 常见问题与排障技巧实录React Native 应用的真实痛点复盘聊了这么多大厂案例和选型思路我们再落地到实际操作。不管你是坚持用 RN还是正在从 RN 迁移原生有一些 RN 开发中最常踩的坑值得提前备好药。这里我结合热搜词里大家最关心的几个问题整理一份可直接参考的排障实录。5.1 启动白屏最诡异的用户第一印象杀手RN 启动白屏是一个非常经典的问题各个技术社区里每天都有人在问。它的本质是 RN 应用在原生启动页消失之后、JS 业务代码首次执行完成之前出现了一段空白期。白屏的时间长短与 JS Bundle 大小、设备性能、首屏加载的数据量强相关。我的排查经验是要分两层看第一层是原生侧的启动快慢第二层是JS 侧的执行效率。原生侧检查 MainActivity 的主题是否设置了合适的 windowBackground很多人建议在启动页阶段就用一个和页面底色一致的图片或背景色来占位至少用户感知上不会有白闪。如果是 Release 包启动明显慢优先看 JS Bundle 的体积。建议在打包时开启 bundle 分包、压缩和资源裁剪能有效降低解析成本。如果首屏还需要请求接口再渲染数据记得在请求没回来前就给出骨架屏。骨架屏可以是原生组件也可以是 RN 页面首帧的静态视图目的是让用户觉得页面已经打开正在加载而不是卡死在白屏。提示把 Metro 的 dev server 关掉再打 Release 包很多本地调试看不出白屏问题的案例都是因为 debug 包和 release 包的启动链路差异巨大。问题一定以 release 包为准。5.2 列表性能优化为什么滑动总是掉帧React Native 性能问题里列表绝对是重灾区几乎占了线上性能报告的一半以上。FlatList 虽然和 ScrollView 相比已经有很大优化但它内部的虚拟化调度依然会带来额外的计算成本。我常用的优化组合拳是第一开启 getItemLayout。如果你的列表项高度是固定的显式告诉 FlatList 每一项的高度它就不需要动态测量每一帧的布局能显著减少滚动时的计算量。第二用 React.memo 包裹列表项组件避免父组件状态更新导致所有行节点重复渲染。第三不要在 renderItem 里写复杂的内联函数每次渲染都会重新创建函数引用破坏 memo 的生效条件。第四若数据量极大超过几千条可以考虑分页加载 过滤策略而不是试图让 FlatList 一次性接管数万行数据。还有一个很多老手都会忽略的点图片加载。RN 的 Image 组件在低端 Android 设备上的解码速度非常容易成为瓶颈。务必开启缓存策略、合理裁剪图片尺寸避免用 1080p 的大图去填充一个 200×200 的头像框。你可以用外层缩略图路由来处理这类问题比如上传图片时先生成多套尺寸前端按需拉取而不是强迫客户端现场解码大图。5.3 从 RN 到原生迁移最稳妥的小步快跑策略如果你读了 Shopify 的案例后团队也在考虑是否要回归原生我不建议一步到位的大重写。这里分享一个经过验证的渐进迁移流程先选一个性能最敏感、用户投诉最多、业务相对独立的模块作为试点比如首页或订单列表。在原生工程里新建该模块的原生页面通过 Deep Link 或一个开关从 RN 页面跳转到原生页面。设置灰度发布先让内部员工和使用频率最高的核心用户访问原生版页面重点观察崩溃率、页面渲染耗时和用户操作成功率的对比数据。如果试点指标明显优于 RN 版本再逐步扩大迁移范围。每迁一个模块都要单独上线、单独复盘不要一次性合并多个模块的迁移代码。在迁移过程中可以用混合栈的方式让 RN 和原生页面共存用统一的路由层来管理跳转避免用户感受到割裂。这套方案的核心在于降低风险、保留退路。你不会因为某一天突然宣布全量迁移而陷入一旦失败就无法收场的被动局面。每走一步都有数据支撑团队心态也更稳。5.4 一个老生常谈但依然有效的提醒技术选型是动态的不是一劳永逸的最后再补一个自己长期做技术顾问的体会没有永远正确的技术选型只有当时情况下最合适的选型。反应很快的团队会定期用业务现状 团队能力 用户反馈三组数据重新审视当初的决定。React Native 用了 6 年不代表就要永远用它原生开发归来也不意味着再过几年不会因为新的跨端框架涌现而再被挑战。关键不在于押注哪个框架而在于你是否愿意在业务的每个阶段诚实评估当前方案的长期收益和债务。我在实际接触过很多团队后发现最强的技术组织往往不是那些选对了技术栈的团队而是那些发现自己选错了还能及时掉头并且把掉头的成本控制得很好的团队。Shopify 这次给我最大的启发不是不要用 RN而是不要因为沉默成本太高就不敢改变。希望读到这里的你也能在自己的技术决策里保持这份清醒和果断。
返回列表