React中如何检测public目录下是否已添加对应资源?
解决方案:在Create React App中检测/public目录图片是否存在
嘿,这个需求我刚好处理过,结合你不想手动生成文件列表的要求,给你两个靠谱的方向:
一、构建时自动生成文件清单(推荐)
因为你提到可以接受构建阶段做处理,那我们可以用Webpack插件在打包时自动扫描/public下的图片,生成一个文件清单JSON,客户端直接导入这个清单来判断图片是否存在,完全不用手动维护。
具体步骤:
- 安装必要工具
因为Create React App默认隐藏了Webpack配置,我们用craco来修改配置,同时用glob来扫描文件:
npm install @craco/craco glob --save-dev
- 替换启动脚本
在package.json里把默认的react-scripts换成craco:
"scripts": { "start": "craco start", "build": "craco build", "test": "craco test" }
- 编写Webpack插件
在项目根目录创建src/utils/generateAssetList.js,这个插件会扫描/public下的图片并生成清单:
const glob = require('glob'); const fs = require('fs'); const path = require('path'); class GenerateAssetListPlugin { apply(compiler) { // 在构建完成后执行 compiler.hooks.done.tap('GenerateAssetListPlugin', () => { // 扫描/public下的图片文件(可根据需要修改后缀) const imagePaths = glob.sync(path.resolve(__dirname, '../../public/**/*.{png,jpg,jpeg,gif,webp}')); // 提取文件名(因为/public下的文件在生产环境是直接放在根目录的) const imageNames = imagePaths.map(filePath => path.basename(filePath)); // 生成JSON文件到src目录 fs.writeFileSync( path.resolve(__dirname, '../assetList.json'), JSON.stringify({ images: imageNames }, null, 2) ); console.log('✅ 图片清单已生成'); }); } } module.exports = GenerateAssetListPlugin;
- 配置Craco加载插件
在项目根目录创建craco.config.js:
const GenerateAssetListPlugin = require('./src/utils/generateAssetList'); module.exports = { webpack: { plugins: { add: [new GenerateAssetListPlugin()] } } };
- 客户端使用清单
现在每次构建都会自动生成src/assetList.json,你可以在组件里导入它:
import assetList from './assetList.json'; function ImageComponent({ objectId }) { const imageName = `${objectId}.png`; // 假设你的图片命名规则是对象ID+后缀 const imageExists = assetList.images.includes(imageName); if (imageExists) { return <img src={`/${imageName}`} alt={`Object ${objectId}`} />; } else { // 发起REST请求的逻辑 return <div>加载中...</div>; } } export default ImageComponent;
二、轻量备选:用HTTP HEAD请求判断
如果不想折腾构建配置,也可以用客户端的HEAD请求来判断图片是否存在——HEAD请求只返回响应头,不会下载图片本身,比GET请求更高效:
import { useState, useEffect } from 'react'; function ImageComponent({ objectId }) { const [imageExists, setImageExists] = useState(false); const imageUrl = `/${objectId}.png`; useEffect(() => { const checkImageExists = async () => { try { const response = await fetch(imageUrl, { method: 'HEAD' }); setImageExists(response.ok); } catch (err) { setImageExists(false); } }; checkImageExists(); }, [objectId]); if (imageExists) { return <img src={imageUrl} alt={`Object ${objectId}`} />; } else { // 发起REST请求的逻辑 return <div>加载中...</div>; } } export default ImageComponent;
这个方案不用改构建配置,但会多一次HTTP请求,适合图片数量不多的场景。
内容的提问来源于stack exchange,提问作者johndodo
相关产品推荐
相关产品推荐

