React Native 图片加载失败?找不到 assets 文件夹?
2025-03-16 17:31:35
React Native 找不到 assets 文件夹中的图片?
最近,遇到一个怪事:React Native 项目里,src/assets
文件夹中的图片竟然加载不出来!明明路径写对了,却报错说文件不存在。这可真让人头疼。
问题重现
我把一张背景图片 bg1.jpg
放在 src/assets
文件夹,然后在 src/screens/splash/index.js
文件里这样引用:
import {ImageBackground} from 'react-native';
import React from 'react';
export default function SplashScreen() {
return (
<ImageBackground
source={require('../../assets/bg1.jpg')}
resizeMode={'cover'}
style={{flex: 1}}>
</ImageBackground>
);
}
结果,程序报了这样一个错:
None of these files exist:
* bg1.jpg
* src\\assets\\bg1.jpg\\index(.native|.android.js|.native.js|.js|.android.jsx|.native.jsx|.jsx|.android.json|.native.json|.json|.android.ts|.native.ts|.ts|.android.tsx|.native.tsx|.tsx)
更奇怪的是,如果我把图片挪到其他文件夹,比如 screens
,然后把引用路径改成 require('../../screens/bg1.jpg')
,居然就好了!这到底是什么原因呢?
问题原因分析
几经周折,发现问题可能出在这几个方面:
- Metro Bundler 配置问题 : Metro Bundler 是 React Native 的默认打包工具。它可能没有正确地配置来处理
assets
文件夹。 - 缓存问题 : React Native 的打包工具或者模拟器、设备可能会缓存旧的资源信息,导致新的资源无法被正确加载。
- 文件命名/路径错误 : 尽管你说路径没错,但还是有必要再仔细检查一遍,包括大小写、文件扩展名等。
- React Native 项目配置变更影响 : 使用了 React Native CLI 并且重命名了 tsx 文件到 js 文件,可能产生意外影响。
解决方案
针对以上可能的原因,我总结了几个解决办法,大家可以逐一尝试。
1. 清理缓存
缓存问题是经常遇到的。不妨试试把各种缓存都清理一遍:
-
清理 Watchman 缓存:
watchman watch-del-all
-
清理 React Native 打包缓存:
# 对于 React Native CLI 项目 npm start -- --reset-cache # 或者 yarn start --reset-cache #或者在项目跟目录中尝试: rm -rf $TMPDIR/react-*
-
清理 npm 或 yarn 缓存:
npm cache clean --force # 或者 yarn cache clean
-
清理 Android Gradle 缓存:
进入项目的
android
文件夹然后运行:``` ./gradlew clean ```
-
重置模拟器/设备:
- iOS 模拟器: 在模拟器菜单中选择 "Device" -> "Erase All Content and Settings..."。
- Android 模拟器: 在 AVD Manager 中,选中模拟器,点击 "Wipe Data"。
- 真机: 卸载应用,重新安装。
清理完缓存,重新运行项目,看看问题是否解决。
2. 检查 Metro Bundler 配置
有时候,Metro Bundler 默认配置可能无法满足我们的需求。我们可以通过修改 metro.config.js
文件(如果没有就创建一个)来调整配置。
在项目的根目录创建或编辑metro.config.js
文件,可以添加或者更改assetExts 来解决此问题:
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
resolver: {
assetExts: ['jpg', 'jpeg', 'png', 'gif', 'bmp','svg', /* 添加其他需要的图片格式 */],
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
上面代码,我们在 resolver.assetExts
数组中添加了常见的图片格式。
完成这一步,我们需要重启 Metro Bundler,变更才会生效。
进阶技巧
假如你的静态资源文件,并非都放在'assets'中, 还散落在多个不同的文件夹下。
我们可以增加resolver.assetExts
同时,修改transformer.assetPlugins
, 以保证所有资源都被包含其中。
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const path = require('path');
const config = {
resolver: {
assetExts: ['jpg', 'jpeg', 'png', 'gif', 'bmp','svg'],
sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx'], // 确保包含所有可能的源文件类型
extraNodeModules: {
// 在这里添加项目使用到的所有自定义模块
'src': path.resolve(__dirname, 'src'),
'components': path.resolve(__dirname, 'src/components'),
},
},
watchFolders: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules'), // 确保监听 node_modules
// 可以按需增加
],
transformer: {
assetPlugins: ['react-native-svg-transformer'], //如需要svg支持,且安装了对应插件
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
上面的配置, 需要保证,额外需要被解析的文件类型添加在sourceExts
, 同时, 静态文件可能出现的其他位置在extraNodeModules
以及watchFolders
被声明。
这些文件,需要大家按需修改为自己实际项目中使用的路径.
3. 绝对路径引用
另一种方法是使用绝对路径引用图片。虽然不够优雅,但有时能解决问题。
首先,我们需要获取项目的根目录路径。可以借助 path
模块:
// 在项目的工具类或者配置文件中
const path = require('path');
const rootPath = path.resolve(__dirname, '..'); // 假设该文件在 src 目录下
export { rootPath };
然后在需要引用图片的地方:
import {ImageBackground} from 'react-native';
import React from 'react';
import { rootPath } from '../utils'; // 假设工具类文件在 src/utils.js
const path = require('path');
export default function SplashScreen() {
const imagePath = path.join(rootPath, 'src/assets/bg1.jpg');
//或者 imagePath = `file://${rootPath}/src/assets/bg1.jpg`;
return (
<ImageBackground
source={{ uri: imagePath }} // 使用 uri 方式
resizeMode={'cover'}
style={{flex: 1}}>
</ImageBackground>
);
}
这样,我们使用绝对路径来引用图片,绕过了相对路径可能引起的问题。但是这种方案通常被认为是比较糟糕的实践。
4. 重新审查目录和拼写
仔细检查文件路径、文件名和扩展名是否完全一致,包括大小写, 以及在导入时使用的目录分隔符是否正确(Unix-like 系统使用/
,Windows 使用\
,但在 React Native 通常推荐使用/
)。
保证在require调用中的字符串没有空格或其他不可见字符.
5.检查是否安装 react-native-asset
react-native-asset
是一个专门为React Native设计用于链接本地资源到iOS/Android的工具包。当标准做法下无法定位资源时,它有几率处理这种链接难题:
首先,我们需要安装这个工具包
npx install react-native-asset
之后,只需要一个命令,自动连接资源
npx react-native-asset
这个包有时会很方便。但是对于常规,目录明确的情况, 我们不需要使用它.
小结
遇到 React Native 图片加载问题,不要慌。可以先清理缓存试试, 然后不行再去考虑自定义 metro 的 config。当然检查基础拼写也非常关键, 最后, 记得以上调整如果都不生效,重新启动项目让各种配置、清理操作生效. 解决问题的过程,也是我们学习和成长的过程。