as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

了解Vega应用程序的系统套件

了解Vega应用程序的系统套件

基于React Native构建的现代应用程序通常会附带大型的单体JavaScript包。这些捆绑包中包含所有内容,从核心React库到应用程序特定的业务逻辑。不过,这种方法也带来了挑战:应用程序更大,启动更慢,交付错误修复时“摩擦力”也更大。

Vega引入了拆分包系统,在该系统中,常用库位于系统上,应用程序则仅提供其独有的代码。本文探讨了这意味着什么、它为何重要以及它的工作原理。

关于拆分包

传统上,React Native应用程序会发布一个包含以下内容的应用程序包:

  • reactreact-native这样的核心库
  • Vega专属模块
  • 第三方库
  • 您应用程序的代码

使用拆分包时,应用程序包将会分为两部分:

系统(常用)包

该包预安装在设备上,它包含广泛使用的库,例如reactreact-native@amazon-devices/react-native-kepler。有关详细信息请参阅系统分发库。系统包与原生Vega运行时保持同步。

拆分应用程序包

您的应用程序包减去常用库。其中仅包含应用程序专属代码和任何专属依赖项。

如何转化

以下是如何拆分单体包的简化示意图:

┌────────────────────────────┐
│ 单体应用程序包 │
│(React、RN、Vega、应用程序)│
└────────────────────────────┘
              │
              ▼
 ┌────────────────────┐    ┌─────────────────────┐
 │ 系统包 │ │ 拆分应用程序包 │
 │ (React、RN、Vega) │ │(应用程序专属代码)│
 └────────────────────┘    └─────────────────────┘

在运行时,Vega首先加载系统包,然后将之拼接到您拆分出的应用程序包中。

为什么拆分包很重要

拆分包可带来几个关键优势:

  • 应用程序更小 — 从应用程序包中移除常用库可将其大小减少1MB或更多。
  • 启动时间 (TTFD) 更快 — 核心库已预装在设备上,可将应用程序初始化时间缩短约100至150ms。
  • 自动错误修复 — 由于系统库是独立更新的,因此无需发布新的应用程序版本即可修复错误并提高性能。
  • 兼容性问题更少 — JS和原生组件都位于同一系统版本中,可确保兼容性。

拆分包机制的工作原理

在底层实现上,拆分包机制依赖于扩展Metro,它是React Native使用的JavaScript打包工具。通常,Metro会生成一个包含所有应用程序代码和依赖项的单一index.bundle包。为启用拆分,Vega对Metro的序列化器阶段进行了自定义改造,该阶段负责控制如何将模块组合成包。

为实现这一点,需用到两个关键钩子:

processModuleFilter

  • 筛除系统包中已提供的模块。
  • 确保应用程序包不会重复包含诸如reactreact-native这类库。

createModuleIdFactory

  • 用于为模块分配一致的确定性ID,确保系统包和应用程序包在共享代码时引用相同的模块ID。
  • Vega不使用Metro的默认增量ID,而是使用基于哈希的方案(例如模块路径的SHA-256)来保证其在构建过程中的稳定性。
                     构建时                        运行时
                  ──────────────────►               ───────────────►
┌─────────────┐    ┌──────────────┐   使用 ID 于   ┌───────────────┐
│ 源包      │─►  │  核心包 │───────────────► │ 加载核心包     │
│ (应用 + 库) │ │ (React, RN, │ │ (系统级) │
└─────────────┘    │  Vega)       │                 └───────────────┘
                   └─────┬────────┘
                         │ 写入 modules.txt
                         ▼
                   ┌──────────────┐   使用 ID 于   ┌───────────────┐
                   │ 库包 │───────────────► │ 加载库包│
                   │(例如 rnsCRN)│ │(系统级)│
                   └─────┬────────┘                 └───────────────┘
                         │ 重复使用 ID / 过滤
                         ▼
                   ┌──────────────┐                 ┌───────────────┐
                   │ 应用包  │───────────────► │ 加载应用包      │
                   │(拆分)│ │(在之上)│
                   └──────────────┘                 └───────────────┘

包的类型

分包系统创建了三类主要的包:

核心包(系统级)

  • 包含重要的基础库 (react, react-native, @amazon-devices/react-native-kepler),
  • 它是首先生成的,会创建一个modules.txt文件,用于将模块路径映射到ID,
  • 从而保障后续依赖包中的模块引用保持一致。

库包(系统级)

  • 适用于常见的库,例如react-native-reanimatedreact-native-screens
  • 构建时会利用核心包所创建的modules.txt,以避免重复打包已经打包的依赖项。
  • 会为每个库包生成额外的modules.txt文件。

应用包(拆分后的应用包)

  • 您的应用程序代码会经过过滤,剔除掉系统包中已包含的任何内容。
  • 通过共享的统一ID来引用系统提供的模块。

构建时会生成诸如keplerscript-app-system-bundles-config.json之类的元数据,告诉Vega您的应用需要哪些系统包。运行时,Vega会先加载系统包,再将应用包挂载到之上。

依赖项与版本管理

分包机制的一大核心挑战就是依赖版本管控:

  • 如果系统预装包内置的是react-native-screens@2.0.0, 但你的应用需要的是2.1.0,将可能引发冲突。
  • 为解决这类冲突,Vega在内部采用带版本标识的模块路径,例如react-native-screens__2/
  • 仅会将主要版本编码到路径中,例如 __2/,因此从2.0.02.0.1这类补丁更新,不会破坏兼容性,也不会强制应用程序重新构建。

筛选依赖项时:

系统包会包含自己的依赖项,例如lodash,但不会在modules.txt中予以列出。因此,如果应用程序也依赖于相同版本的lodash,则它仍存在于应用程序包中,以防止系统库升级时意外损坏。

主要版本相同,可安心升级:@amzn /react-native-screens__2/... (2.0.0 → 2.0.1 的升级,不会改变路径)

主要版本不同,则特意区分:@amzn /react-native-screens__3/...

这套方案搭配稳定的模块ID机制,能让系统包高频迭代更新的同时,始终保持与应用的兼容性。

系统包构建全生命周期

以下是分包构建的完整生命周期:

  1. 生成核心包 — 包含React、React Native和Vega模块。
  2. 生成库包 — 使用基于核心包的modules.txt的依赖项感知过滤。
  3. 生成应用程序包 — 删除系统已提供的所有模块。
  4. 生成元数据 — 列出应用程序需要哪些系统包。
  5. 加载Vega — 首先加载系统包,然后挂载应用程序包。

最终形成模块化体系,让应用体积更小、启动更快,同时对底层库版本更新具备更强的抗干扰能力。


Last updated: 2026年4月16日