鬼故事
46.88MB · 2025-10-29
在项目开发过程中,产品详情页的图片加载出现了一个典型的环境差异问题:在开发环境(本地调试)中,图片能正常显示;但当使用 Vite 进行生产打包构建后,详情页的图片却全部无法加载。这一问题直接影响了产品的展示效果,需要快速定位并解决。
要解决这个问题,首先需要理解开发环境与生产环境的核心差异 ——Vite 对静态资源的处理方式。
在开发环境中,Vite 会直接使用资源的原始路径进行加载,此时图片文件的名称(如A_01.jpg)和路径保持不变。而项目原始的图片加载逻辑(productImages.ts)正是基于这种 “固定路径” 设计的:
typescript
// 原始逻辑:基于固定路径匹配加载图片
const GatewayImages = import.meta.glob('@Gateway/**/*.jpg', {
eager: true,
import: 'default'
}) as Record<string, string>
const PlusImages = import.meta.glob('@Plus/**/*.jpg', {
eager: true,
import: 'default'
}) as Record<string, string>
这段代码通过import.meta.glob按路径匹配导入图片,并依赖路径中的文件名和文件夹结构进行筛选排序。
但在生产构建时,Vite 为了优化缓存和资源管理,会对静态资源进行哈希化重命名(如将A_01.jpg重命名为A_01-BB7YyWF4.jpg),这一过程在vite.config.ts中通过配置明确指定:
typescript
build: {
rollupOptions: {
output: {
// 静态资源分类打包,包含哈希值
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
...
}
}
},
哈希化后,原始路径中的文件名被修改,导致依赖 “固定路径字符串匹配” 的逻辑彻底失效 —— 代码无法再通过原始文件名找到对应的图片资源,最终表现为生产环境图片无法显示。
要解决这个问题,核心思路是让图片加载逻辑不依赖具体的路径或文件名格式,转而通过 “产品标识” 与 “图片资源” 建立直接映射。具体实现如下:
不再按文件夹(@Gateway/@Plus)拆分导入,而是一次性导入所有产品图片,避免路径分割导致的匹配问题:
typescript
// 导入所有产品图片(无论所在文件夹)
const allImages = import.meta.glob('@product/**/*.jpg', {
eager: true,
import: 'default'
}) as Record<string, string>
创建一个映射结构(ProductImagesMap),将 “产品 ID” 和 “图片尺寸” 直接关联到对应的图片 URL 数组,实现 “按标识查找” 而非 “按路径匹配”:
typescript
// 定义映射结构:产品ID -> 尺寸 -> 图片URL数组
interface ProductImagesMap {
[productId: string]: {
[size: string]: string[]
}
}
const productImagesMap: ProductImagesMap = {}
通过正则表达式从图片的原始路径中提取产品系列、尺寸、产品 ID 等核心信息,忽略具体的文件名(因为文件名会被哈希化),只保留稳定的标识信息:
typescript
// 构建产品图片映射
Object.entries(allImages).forEach(([path, url]) => {
console.log(`路径: ${path}, URL: ${url}`);
// 从路径中提取产品信息
// 路径格式示例: /src/assets/images/product/Nano/1000/Nano-CPN-3528A/A_01.jpg
const match = path.match(//product/([^/]+)/(d+)/([^/]+)/([^/]+).jpg/)
if (match) {
const [, series, size, productFolder, filename] = match
console.log(`匹配成功 - 系列: ${series}, 尺寸: ${size}, 产品文件夹: ${productFolder}, 文件名: ${filename}`);
// 从产品文件夹名中提取产品ID (如 'Nano-CPN-3528A')
const productId = productFolder
// 确保映射结构存在
if (!productImagesMap[productId]) {
productImagesMap[productId] = {}
}
if (!productImagesMap[productId][size]) {
productImagesMap[productId][size] = []
}
// 将图片URL添加到对应的产品ID和尺寸下
productImagesMap[productId][size].push(url)
console.log(`添加图片到产品 ${productId} 的 ${size} 尺寸: ${url}`);
} else {
console.warn(`路径匹配失败: ${path}`);
}
})
为了确保图片展示顺序与开发环境一致,可对图片数组进行排序(例如按原始文件名中的序号排序):
typescript
// 对每个产品、每个尺寸的图片数组排序(示例:按文件名中的数字序号)
Object.values(productImagesMap).forEach(sizeMap => {
Object.values(sizeMap).forEach(images => {
images.sort((a, b) => {
// 从URL中提取原始文件名(忽略哈希部分)
const aName = a.split('/').pop()?.split('-')[0] || ''
const bName = b.split('/').pop()?.split('-')[0] || ''
// 按文件名中的数字排序(如A_01、A_02)
return parseInt(aName.match(/d+/)?.[0] || '0') - parseInt(bName.match(/d+/)?.[0] || '0')
})
})
})
重构后的图片加载逻辑具有以下优势:
2025-10-30
国产类魂游戏《明末:渊虚之羽》今日上线,Steam 国区 248 元起
2025-10-30
国产游戏《明末:渊虚之羽》首发 Steam“差评如潮”:被指灾难级优化、环国区永久降价