文章目录
-
- 一、前言
- 二、Metro生命周期
-
- [2.1 解析(Resolution)](#2.1 解析(Resolution))
- [2.2 转换(Transformation)](#2.2 转换(Transformation))
- [2.3 序列化(Serialization)](#2.3 序列化(Serialization))
- 三、拓展阅读
一、前言
众所周知,Metro
是 React Native
默认的 JavaScript 打包模块。对于前端项目,打包工具已有webpack
(大而全,图片代码打包),rollup
(专攻代码打包,框架场景常见)等,既然有这些打包工具为什么还要在移动端搞一个metro
,其中一个原因为ram bundle
,iOS采用indexed ram bundle
读取一个文件效率更高,Android采用file ram bundle
。
二、Metro生命周期
metro
的bundling
有三个阶段:
- 解析 (
Resolution
): 解析所有模块并且构建成图,有点类似于Gradle在配置阶段会将所有相互依赖的任务构建成图。 - 转换 (
Transformation
):转换阶段会将模块转换成目标平台能识别的格式,这一阶段执行了js编译,主流常用的js编译器为babel
。 - 序列化 (
Serialization
):最后一个阶段序列化,会将所有转换之后的模块打包成一个或者多个bundle
。
2.1 解析(Resolution)
在Gradle 配置阶段我们常看到assets
、aidl
、res
、java
的配置。
javascript
android{
...
sourceSets {
main {
java.excludes = [
'**/build/**',
]
srcDirs.forEach {
assets.srcDirs += "$projectDir/$it/main/assets"
aidl.srcDirs += "$projectDir/$it/main/aidl"
res.srcDirs += "$projectDir/$it/main/res-frame-animation"
res.srcDirs += "$projectDir/$it/main/res"
java.srcDirs += "$projectDir/$it/main/java"
}
}
}
...
}
metro
与之对应项为assetExts
、sourceExts
。
2.2 转换(Transformation)
在ram bundle
的启动优化中,通过getTransformOptions
可以实现模块预加载,而其他的模块按需加载从而提高启动速度。
javascript
function getTransformOptions(
entryPoints: $ReadOnlyArray<string>,
options: {
dev: boolean,
hot: boolean,
platform: ?string,
},
getDependenciesOf: (path: string) => Promise<Array<string>>,
): Promise<ExtraTransformOptions> {
// ...
}
type ExtraTransformOptions = {
preloadedModules?: {[path: string]: true} | false,
ramGroups?: Array<string>,
transform?: {
inlineRequires?: {blockList: {[string]: true}} | boolean,
nonInlinedRequires?: $ReadOnlyArray<string>,
},
};
在preloadedModules
中配置的模块为预加载模块,而其他的模块在ram bundle
按需加载,这一块有点类似于Android multidex
,Android5.0
之前可以将部分类指明到主dex,其他被分配到辅dex。在Android App的构建流程中,编译完之后还会对字节码进行混淆,这块metro也有minifierPath
(默认使用metro-minify-terser
)、minifierConfig
。在混淆这块除了terser
,metro还提供了metro-minify-uglify
。
2.3 序列化(Serialization)
在序列化的阶段模块需要有id
以便于require
导入,创建模块id
的函数为createModuleIdFactory
,而processModuleFilter
决定了过滤掉哪些模块不进入bundle
,所以通过createModuleIdFactory
与processModuleFilter
两个函数可以实现分包。
随着react-refresh
、react-reconciler
相继出现,react hot loader
逐渐被替代,react refresh
的实现与平台无关,React
、React Native
等实现react-reconciler
的自定义渲染器都能使用,而且react refresh
能hot的颗粒度更小。在Web平台使用react refresh
。移动平台则是React Native团队自己实现且内置到了metro
打包器取名fast-refresh
。