公司业务方向的原因,有几个RN项目是几年前了很久没维护了。最近有需要重新发版,于是按照往常打包,工程报错了:
该工程的RN配置环境:
"react": "16.9.0",
"react-native": "^0.61.5"
Loading dependency graph...Failed to construct transformer: Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:80:19)
at Object.createHash (node:crypto:139:10)
at stableHash (/Users/user1/Downloads/ProjectRN/node_modules/metro-cache/src/stableHash.js:19:8)
at JsTransformer.getCacheKey (/Users/user1/Downloads/ProjectRN/node_modules/metro/src/JSTransformer/worker.js:471:7)
at getTransformCacheKey (/Users/user1/Downloads/ProjectRN/node_modules/metro/src/DeltaBundler/Transformer/getTransformCacheKey.js:39:29)
at new Transformer (/Users/user1/Downloads/ProjectRN/node_modules/metro/src/DeltaBundler/Transformer.js:147:28)
at /Users/user1/Downloads/ProjectRN/node_modules/metro/src/Bundler.js:54:29
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
opensslErrorStack: [
'error:03000086:digital envelope routines::initialization error',
'error:0308010C:digital envelope routines::unsupported'
],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
error Cannot read properties of undefined (reading 'transformFile'). Run CLI with --verbose flag for more details.
TypeError: Cannot read properties of undefined (reading 'transformFile')
at /Users/user1/Downloads/ProjectRN/node_modules/metro/src/Bundler.js:87:34
at Generator.next (<anonymous>)
at asyncGeneratorStep (/Users/user1/Downloads/ProjectRN/node_modules/metro/src/Bundler.js:14:24)
at _next (/Users/user1/Downloads/ProjectRN/node_modules/metro/src/Bundler.js:34:9)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
解决办法:
1、设置export NODE_OPTIONS=--openssl-legacy-provider
这是网上查找到的比较多的解决方法。
【分析】:(1)主要是node.js 的版本问题导致这个错误。因为 node.js V17版本中最近发布的OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响。故此以前的项目在升级 nodejs 版本后会报错。(2)设置NODE_OPTIONS=--openssl-legacy-provider主要是告诉nodejs,别使用最新的SSL3.0,还是使用以前旧版本的。(3)我电脑上的nodejs版本为:21.7.3。于是我尝试node这方面试试解决。
【实践】:有两个方法设置,一个是在命令行进行设置,但是这个设置只针对当前终端窗口生效。关闭窗口后下次再运行还是会报同样的错。
第二个方法是在RN项目的ios项目中进行设置(在这里设置可以达到一劳永逸的效果):
(1)进入RN项目的ios文件夹,Xcode打开iOS项目(打开.xcworkspace文件)
(2) target -> build phases -> bundle react native code and images
添加:export NODE_OPTIONS=--openssl-legacy-provider
【结果】:我命令行和XCode都进行了设置,但是报错还在。所以推断不是node版本的问题。也看到有的人降级了node 版本为16/以下解决了问题的。所以我这里应该不用降级node版本
nodejs新版本引起的:digital envelope routines::unsupported
2、修改metro-cache中使用的hash函数,兼容node 17
如下路径【ProjectRN/node_modules/metro-cache/src/stableHash.js】找到stableHash.js文件,找到stableHash 方法,修改其使用的hash函数(md4改为md5)
手动直接在项目 node_modules 下对源码直接修改的话重新安装就会失效,不方便维护使用。可以使用patch-package类似的工具进行安全修改。
【结果】:成功解决
【参考链接】:
踩过的坑:
1、一开始,因为这个报错不属于业务代码的报错,于是判断应该是环境出了问题,命令行运行【react-native doctor】,结果如下:
结果显示Watchman版本不支持。按照上面的提示 输入了【e】,并没有解决问题。那就得降级Watchman版本。然而brew 不支持对Watchman 指定版本下载。网上搜索了几个安装Watchman 4.9.0的办法。最后操作下来都是安装不上4.9.0。附上几个知道安装Watchman 4.9.0的文章:
(1)如何在降级watchman | online阳光-专注于大前端行业领域
在这个文章中提到找到4.9.0提交的commit提交记录。然而如今是没有这个4.9.0提交的commit提交记录了,也找不到了,用文章中的commit code也是用不了
(2)WatchmanUnavailable("Watchman 4.9 or later is required.")的处理方案-代码阁
这两篇文章都是下载Watchman 4.9.0的安装包,解压后进行手动安装。但是我这边每次在make阶段都报错,最后也是安装失败。4.9.0版本是在2019年那段时间的了,应该是时间太久远了,电脑很多包都是更新了。所以安装不上。
【结论】:react-native doctor提示的需要安装watchman4.9.0版本兼容报错是无效的,watchman版本是多少都不会影响项目运行(版本不过低就行)
2、在解决问题的过程中,有需要访问到一些国外的网站,需要设置host。可以参考文章中的方法进行设置,挺方便:如何解决类似 curl: (7) Failed to connect to raw.githubusercontent.com port 443: Connection refused 的问题 · Issue #10 · hawtim/hawtim.github.io · GitHub