问题背景:开发与生产环境的图片显示差异

在项目开发过程中,产品详情页的图片加载出现了一个典型的环境差异问题:在开发环境(本地调试)中,图片能正常显示;但当使用 Vite 进行生产打包构建后,详情页的图片却全部无法加载。这一问题直接影响了产品的展示效果,需要快速定位并解决。

问题根源: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]',
      ...
    }
  }
},

哈希化后,原始路径中的文件名被修改,导致依赖 “固定路径字符串匹配” 的逻辑彻底失效 —— 代码无法再通过原始文件名找到对应的图片资源,最终表现为生产环境图片无法显示。

解决方案:重构图片加载逻辑,摆脱路径依赖

要解决这个问题,核心思路是让图片加载逻辑不依赖具体的路径或文件名格式,转而通过 “产品标识” 与 “图片资源” 建立直接映射。具体实现如下:

1. 统一导入所有产品图片

不再按文件夹(@Gateway/@Plus)拆分导入,而是一次性导入所有产品图片,避免路径分割导致的匹配问题:

typescript

// 导入所有产品图片(无论所在文件夹)
const allImages = import.meta.glob('@product/**/*.jpg', {
  eager: true,
  import: 'default'
}) as Record<string, string>

2. 构建产品图片映射表

创建一个映射结构(ProductImagesMap),将 “产品 ID” 和 “图片尺寸” 直接关联到对应的图片 URL 数组,实现 “按标识查找” 而非 “按路径匹配”:

typescript

// 定义映射结构:产品ID -> 尺寸 -> 图片URL数组
interface ProductImagesMap {
  [productId: string]: {
    [size: string]: string[]
  }
}

const productImagesMap: ProductImagesMap = {}

3. 从路径中提取关键信息,填充映射表

通过正则表达式从图片的原始路径中提取产品系列、尺寸、产品 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}`);
  }
})

4. 保持图片显示顺序的一致性

为了确保图片展示顺序与开发环境一致,可对图片数组进行排序(例如按原始文件名中的序号排序):

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')
    })
  })
})

方案优势:适配 Vite 构建特性,提升逻辑稳定性

重构后的图片加载逻辑具有以下优势:

  1. 摆脱路径依赖:不再依赖具体的文件名或路径格式,即使 Vite 对资源重命名(加哈希),也能通过稳定的 “产品 ID” 和 “尺寸” 找到图片。
  2. 适配构建特性:完全兼容 Vite 的静态资源处理机制,开发 / 生产环境表现一致。
  3. 逻辑更清晰:通过映射表直接关联 “产品标识” 与 “图片资源”,避免复杂的路径字符串匹配,降低维护成本。
  4. 扩展性更强:新增产品图片时,无需修改加载逻辑,只需按统一目录结构存放即可自动被识别。
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]