时间过得真快,转眼间就2021年了,这段时间工作比较忙,但还是抽空将工作中的经验总结分享给大家,希望大家在新的一年里都能有所收获~
一、metro 的缓存机制
1、为什么要缓存
react-native 在执行 react-native start
或者 react-native bundle
命令的时候,都会有缓存。
目的其实很简单,metro 在打包的时候需要将 TS
和 ES6/7
的代码转换为 ES5
的目标代码。
那如果一个文件没有任何变更,这个时候我们就不需要去转换它了,所以 metro 设置了一套文件缓存机制来优化编译转换速度 。
2、两种缓存机制
metro 的缓存实现在 node_modules/metro-cache
中,主要有两种缓存机制:
- 服务端缓存:HttpStore
- 本地缓存:FileStore
服务端主要是通过服务器来缓存相关内容,优势是不用担心缓存的大小和时间限制,可以灵活的设置缓存策略,不过这个我们目前没有使用到,后期可以考虑。
metro 默认的缓存机制是 FileStore,这也是我们目前使用的缓存机制,FileStore 实际上就是将编译转换后的文件缓存起来,以便下一次编译的时候能够避免重复转换,加快编译速度。
3、FileStore 缓存原理
FileStore 缓存的原理其实很简单:
- 缓存的key:表名 + 文件内容映射生成的 hash 值
- 缓存的内容:转换后的文件内容
当执行转换的时候,如果发现文件的 hash 值存在,那么就说明文件内容没有发生变化,就不会去执行转换操作, 大大节省了编译时间。FileStore 为了避免 hash 碰撞,采用了分表存储,具体可以查看 FileStore.js
的源代码来了解更多。
二、metro 缓存到哪里去了
知道了 metro 的缓存机制,那么这个缓存到底存储在本地系统的什么位置呢?
查看 FileStore.js
源代码发现初始化 FileStore 时会传入一个 root 参数,这个 root 其实就是缓存存储的路径。所以我们只要知道 FileStore 在哪里初始化的,就能知道缓存的地址了。
在 start 的时候我们没有指定 metro 的配置,所以 metro 的配置都是从 node_modules/metro-config/defaults/index.js
中读取的默认配置,在这里可以看到缓存的初始化代码,如下:
cacheStores: [
new FileStore({
root: path.join(os.tmpdir(), "metro-cache")
})
]
缓存路径为 os.tmpdir() 拼接上 "/metro-cache"
那这个 os.tmpdir()
是什么呢?os 是 node.js 的一个系统库,tempdir()
获取的是系统的临时目录,其值等于在 Linux 终端下执行如下命令获取的值:
echo $TMPDIR
最终得出缓存地址为:echo $TMPDIR 拼接上 "/metro-cache",大家可以自行尝试查看。
image2021-1-21_16-55-9.png三、缓存导致的问题及解决方案
1、问题
react-native 的缓存会导致各种问题,常见的问题为更新了依赖库,团队中有的小伙伴能正常运行,有的缺报莫名其妙的错误,这是在执行 npm start
时缓存带来的问题,实际上执行 react-native bundle
打包也会有缓存问题,所以问题从大类来讲有以下两类:
1. 修改了依赖库,团队中有的小伙伴能正常运行,有的则报出莫名其妙的错误
2. react-native bundle 打包偶现 找不到 metro-cahce/T/xxxx 文件错误
这两类问题都是由于 metro 缓存导致的。
2、解决方案
既然是缓存问题,那么清除缓存就能够解决问题,有以下几种方案来清除缓存:
-
重启电脑:
tempdir
目录是一个临时目录,在重新电脑之后实际上就会被清除,所以tempdir
目录下的 metro-cache 目录也会被清除 -
手动删除缓存:终端执行
echo $TMPDIR
获取 临时目录,再拼接上 metro-cache 得到缓存目录,手动删除 metro-cache 目录即可 -
自动删除缓存:metro打包提供了不少参数,其中就有一个清除缓存的参数,只需在执行
start
和bundle
时带上--reset-cache
即可自动删除缓存
react-native start --reset-cache
react-native bundle --reset-cache
删除缓存之后再次编译或者打包时都会变慢,所以一般情况下无需删除缓存。
本篇为原创文章,希望大家多多支持,转载请注明出处,谢谢~
网友评论