logo头像

我有一个梦想

metro打包分析及热更新初探

本文于 1648 天之前发表,文中内容可能已经过时。

定义:打包工具

react-native在0.5版本以后引入metro-bundler工具打包

在对每个模块进行捆绑时,每个模块都会分配一个固定的id,意味着不能动态更新(导入组件的顺序发生变化,或者依赖版本做了更新),将id转化为module的路径

打包流程

选项 描述
entry-file 根JS文件的绝对路径
output 文件名存储输出的位置,例如 /tmp/dependencies.txt
platform 用于选择模块的平台扩展
transformer 指定要使用的自定义转换器
max-workers 指定工作池将为转换文件生成的最大工作器数。默认为计算机上可用的核心数。
dev 如果为false,则跳过所有dev-only代码路径
verbose 启用日志记录

高速缓存

Metro具有多层缓存:您可以设置多个缓存供Metro使用而不是一个。这有几个优点,在这个页面上我们将解释缓存如何工作。

添加global.DEV变量区分打包的执行环境

(release) __DEV__ = false

bundle中使用Number(int)数值型以_d的方式定义了代码模块ID,并使用_r的方式进行依赖行。如果存在模块间的改变或者修改,都有可能导致模块ID发生改变,导致旧的bundle文件不能使用。所以在拆分公共部分与业务部分的过程中,需要我们解决模块间依赖的问题。

热更新

拆包>>>>>comm打diff包>>>>>>整合包

-d:define (简单理解为模块)包括RN框架源码 js 部分、自定义js代码部分、图片资源信息,供 require 引入使用

-r:require 找到 __d 定义的代码块 并执行

拆包(基础包和业务包)

原先以moduleId作为参数传递,现在改为moduleName(module的路径)

  1. 0.5 <= version < 0.52
  2. 0.52 <= version <= 0.55
  3. 0.56 <= version

comm打出diff包

comm 可以用于两个文件之间的比较,它有一些选项可以用来调整输出,以便执行交集、求差、以及差集操作。

  • 交集:打印出两个文件所共有的行。
  • 求差:打印出指定文件所包含的且不相同的行。
  • 差集:打印出包含在一个文件中,但不包含在其他指定文件中的行。
1
2
3
-1:不显示在第一个文件出现的内容;
-2:不显示在第二个文件中出现的内容;
-3:不显示同时在两个文件中都出现的内容。

使用comm命令生成diff包

整合

初始化RN环境时就加载基础包,后续添加模块功能时只需要添加模块功能的diff包即可,在任更新的应用是,在需要热更新时,下载最新diff包去替换原先diff包,重新启动后应用最新diff包即可

  1. 包的合并
  2. diff包合并到diff包(重复的问题的处理)

为什么要使用路径代替moudleId进行引用

metro-bundler 打包处理模块时,以递增的方式给每个模块一个 module ID,使得文件直接通过 require(module ID) 的方式引用其他模块;当然,一个项目的所有模块都在一个 bundle 中是没问题的,但进行 bundle 拆分后,当框架新增或删除一个依赖时,因为模块编号的方式使得在该状况下,后续的模块的 module ID 将会错位,这将造成升级框架 bundle 的难度,每次升级,其他业务 bundle 相应的需要回归测试,加大了开发测试成本。我们的选择是直接舍弃 module ID 的引用方式,直接使用模块路径进行引用,这样无论怎么增减模块,都不会出现模块引用错误的问题,做法也比较简单,重写了 resolutionResponse.getModuleId 方法,虽然会增大一点 bundle 的 size。

问题: LoadBridge 和 ReactActivity的重写需要在com.facebook.react的报名下,否则会报错

结论:metro例子实现,无法使用google-diff合并diff包,所以metro完全是一个拆包方案,配合使用google-diff的热更新方案可以实现rn的热更新。