You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目执行npm run build后图片无法加载问题求助

React构建后商品图片无法加载问题

问题现象

  • 开发阶段应用运行正常,无任何报错,但执行npm run build构建生产版本后,商品图片和分类图片无法显示
  • 仅通过CSS设置为背景图的banner能正常加载
  • 构建后apple-images目录未被完整打包到输出目录的media文件夹中,只有banner图片被提取
  • 浏览器控制台返回404错误,提示无法找到对应图片文件

截图说明

  • 示例商品截图:页面内商品图片位置显示空白占位,无图片内容
  • 图片调用方式截图:代码中直接使用字符串形式的相对路径引用图片
  • 控制台截图:显示"Not Found"错误,路径指向未被打包的图片位置
  • 文件夹结构截图:项目中apple-images目录包含shop-items(商品图片)和store-image(分类图片)子目录

相关代码片段

StoreData.js(图片路径定义)

export const storeData = [
  {
    type: "Mac",
    product: [
      {
        name: "MacBook Air avec puce M1",
        prix: 1199,
        screen: " 13.3 pouces",
        puce: "Puce Apple M1",
        RAM: "8 Go ou 16 Go de mémoire unifiée",
        stockage: "256 Go à 2 To de stockage",
        autonomie: "jusqu'à 18 heures d'autonomie",
        gadgets: "Touch ID, Touch bar",
        options: {
          stockage: {
            taille1: { taille: "256 Go", prix: 0 },
            taille2: { taille: "512 Go", prix: 230 },
            taille3: { taille: "1 To", prix: 460 },
            taille4: { taille: "2 To", prix: 920 },
          },
          RAM: {
            taille1: { taille: "8 Go", prix: 0 },
            taille2: { taille: "16 Go", prix: 230 },
          },
        },
        dimensions: {
          Hauteur: "0.41 à 1.61 cm",
          Largeur: "30.41cm",
          Profondeur: "21.24cm",
          Poids: "1.29 kg",
        },
        exploitation: "macOS",
        productImage: "./apple-images/shop-items/mac-book-air.jpg",
      },
      {
        name: 'MacBook Pro 13"',
        prix: 1599,
        screen: " 13.3 pouces",
        puce: "Puce Apple M2",
        RAM: "8 Go à 24 Go de mémoire unifiée",
        stockage: "256 Go à 2 To de stockage",
        autonomie: "jusqu'à 20 heures d'autonomie",
        gadgets: "Touch ID , Touch Bar",
        options: {
          stockage: {
            taille1: { taille: "256 Go", prix: 0 },
            taille2: { taille: "512 Go", prix: 230 },
            taille3: { taille: "1 To", prix: 460 },
            taille4: { taille: "2 To", prix: 920 },
          },
          RAM: {
            taille1: { taille: "8 Go", prix: 0 },
            taille2: { taille: "16 Go", prix: 230 },
          },
        },
        dimensions: {
          Hauteur: "1.56cm",
          Largeur: "30.41cm",
          Profondeur: "21.24cm",
          Poids: "1.4 kg",
        },
        exploitation: "macOS",
        productImage: "./apple-images/shop-items/macbookPro.png",
      },
    ],
    frontImage: "./apple-images/store-image/mac.png",
  }
];

StoreComponent.jsx(图片调用代码)

import React, { useState, useEffect } from "react";
import StoreContext from "./storeContext";
import { storeData } from "./StoreData.js";
import BuyModal from "./BuyModal.jsx";
import Cart from "./Cart.jsx";
import { v4 as uuidv4 } from "uuid";

export function StoreComponent({ Data }) {
  let prevType = null;
  const [selectedType, setSelectedType] = useState(null);
  const [selectedProducts, setSelectedProducts] = useState([]);
  const [selectedItem, setSelectedItem] = useState([]);
  const [ShowModal, setShowModal] = useState(false);
  const [isClicked, setIsClicked] = useState(false);
  const [showBlurBackground, setShowBlurBackground] = useState(false);
  const [newConfig, setNewConfig] = useState({});
  const [cartItems, setCartItems] = useState([]);

  const handleAddToCart = () => {
    const newId = uuidv4();
    setCartItems([...cartItems, { ...newConfig, id: newId }]);
    console.log(cartItems);
  };

  const handleClick = (name) => {
    setShowModal(true);
    setShowBlurBackground(true);
    const product = storeData
      .filter((item) => item.product.find((p) => p.name === name))
      .flatMap((item) => item.product)
      .find((p) => p.name === name);
    const serializedObject = JSON.stringify(product);
    setSelectedItem(serializedObject);
  };

  const handleClickCart = () => {
    setIsClicked(true);
  };

  const handleClose = () => {
    setIsClicked(false);
    setShowModal(false);
    setShowBlurBackground(false);
  };

  const onStoreSelectorClick = (type) => {
    setSelectedType(type);
    const products = storeData
      .filter((item) => item.type === type)
      .flatMap((item) => item.product);
    setSelectedProducts(products);
  };

  useEffect(() => {
    onStoreSelectorClick("Mac");
  }, []);

  return (
    <StoreContext.Provider value={{ newConfig, setNewConfig }}>
      <div>
        <div
          className={`StoreNav ${showBlurBackground ? "blurred-background" : ""}`}
        >
          {storeData &&
            storeData.map((item, index) => {
              if (item.type !== prevType) {
                prevType = item.type;
                return (
                  <div
                    className={`StoreSelector ${selectedType === item.type ? "active" : ""}`}
                    type={item.type}
                    key={index}
                    onClick={() => onStoreSelectorClick(item.type)}
                  >
                    <img className="categorie" src={item.frontImage} alt="" />
                    <p>{item.type}</p>
                  </div>
                );
              }
              return null;
            })}
        </div>
        <div className="ItemsWrap">
          {selectedProducts.map((product, index) => (
            <div
              className={`item ${showBlurBackground ? "blurred-background" : ""}`}
              key={index}
            >
              <h1>{product.name}</h1>
              <div className="images">
                <img className="itemImg" src={product.productImage} alt="" />
              </div>
              <div className="text">
                <p>A partir de {product.prix}€</p>
                <button
                  className="Buy"
                  onClick={() => handleClick(product.name)}
                >
                  Acheter
                </button>
              </div>
            </div>
          ))}
          {ShowModal && (
            <BuyModal
              products={selectedItem}
              onClose={handleClose}
              onAdd={handleAddToCart}
            />
          )}
          <Cart
            onClose={handleClose}
            onOpen={handleClickCart}
            isClicked={isClicked}
            Items={cartItems}
            setCartItems={setCartItems}
          />
        </div>
      </div>
    </StoreContext.Provider>
  );
}

解决方案

React项目(尤其是Create React App创建的项目)中,直接使用字符串形式的相对路径引用图片时,构建工具无法识别这些路径,不会将对应的图片文件打包到生产目录中。只有通过import或require引入的图片资源,才会被构建工具处理,替换为正确的生产环境路径。

方法1:使用require动态加载图片

修改StoreData中的图片路径,用require包裹并获取default属性:

export const storeData = [
  {
    type: "Mac",
    product: [
      {
        // ...其他属性
        productImage: require("./apple-images/shop-items/mac-book-air.jpg").default,
      },
      {
        // ...其他属性
        productImage: require("./apple-images/shop-items/macbookPro.png").default,
      },
    ],
    frontImage: require("./apple-images/store-image/mac.png").default,
  }
];

方法2:提前import所有图片

在StoreData.js顶部先导入需要的图片,再将导入的变量赋值给对应属性:

import macBookAirImg from "./apple-images/shop-items/mac-book-air.jpg";
import macBookProImg from "./apple-images/shop-items/macbookPro.png";
import macFrontImg from "./apple-images/store-image/mac.png";

export const storeData = [
  {
    type: "Mac",
    product: [
      {
        // ...其他属性
        productImage: macBookAirImg,
      },
      {
        // ...其他属性
        productImage: macBookProImg,
      },
    ],
    frontImage: macFrontImg,
  }
];

背景图正常显示的原因

CSS中的背景图路径会被构建工具自动解析,工具会将对应的图片文件打包到生产目录,并替换为正确的路径。而JS代码中的字符串路径不会被解析,所以构建后原路径失效,导致图片无法加载。

内容的提问来源于stack exchange,提问作者Nayne1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 00:17:35