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

React项目编译阶段如何获取图片宽高尺寸

问题根源

image-size是Node.js环境专用依赖,基于Node原生fs模块读取本地文件,这类API无法在浏览器端运行。create-react-app(简称CRA)默认webpack配置不会为浏览器端代码polyfill fs等Node原生模块,直接在React组件代码中引入该包必然触发相关报错。

最优实现方案(编译阶段获取尺寸)

该方案完全匹配需求:图片尺寸在应用编译阶段就完成读取,直接写入打包产物,无运行时开销,不需要等浏览器加载图片即可拿到准确像素宽高,最终写法和预期完全一致。
无需eject CRA原生配置,通过自定义webpack loader配合配置覆写工具即可实现:

步骤1:安装必要依赖

npm install @craco/craco image-size --save-dev

步骤2:编写自定义图片处理loader

在项目根目录新建image-size-loader.js文件,在编译环节读取图片尺寸,和图片最终访问路径一起导出:

const sizeOf = require('image-size');
const path = require('path');

module.exports = function imageSizeLoader(source) {
  const filePath = this.resourcePath;
  // 读取图片实际像素尺寸
  const dimensions = sizeOf(filePath);
  // 拼接图片编译后的最终访问路径
  const assetRelativePath = path.relative(this.rootContext, filePath).replace(/\\/g, '/');
  const publicPath = this._compilation.outputOptions.publicPath || '';
  const contentHash = this.utils.createHash('md4').update(source).digest('hex').slice(0, 8);
  const fileExt = path.extname(filePath);
  const outputSrc = `${publicPath}static/media/${assetRelativePath.split('/').pop().replace(fileExt, '')}.${contentHash}${fileExt}`;

  // 导出包含路径、宽高的对象
  return `export default {
    src: ${JSON.stringify(outputSrc)},
    width: ${dimensions.width},
    height: ${dimensions.height}
  }`;
};
// 声明loader接收二进制文件格式
module.exports.raw = true;

步骤3:添加CRA配置覆写文件

在项目根目录新建craco.config.js,将自定义loader匹配到存放本地图片的目录(示例中为src/assets/images,可根据自己的目录结构调整):

const path = require('path');

module.exports = {
  webpack: {
    configure: (webpackConfig) => {
      // 排除CRA默认图片loader对自定义目录的处理
      const rules = webpackConfig.module.rules.find(rule => !!rule.oneOf);
      const defaultImgRule = rules.oneOf.find(item => item.type === 'asset/resource' && item.test && item.test.test('.png'));
      if (defaultImgRule) {
        defaultImgRule.exclude = [path.resolve(__dirname, 'src/assets/images')];
      }

      // 新增自定义loader规则
      webpackConfig.module.rules.push({
        test: /\.(png|jpe?g|gif|webp)$/i,
        include: [path.resolve(__dirname, 'src/assets/images')],
        use: [{ loader: path.resolve(__dirname, 'image-size-loader.js') }]
      });

      return webpackConfig;
    }
  }
};

步骤4:修改项目启动、构建命令

编辑package.json中的scripts字段,将原有的react-scripts命令替换为craco:

{
  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test"
  }
}

步骤5:组件中直接使用

导入图片时即可直接拿到编译阶段注入的宽高属性,直接渲染即可:

import demoImg from './assets/images/demo.png';

function App() {
  return (
    <img
      src={demoImg.src}
      width={demoImg.width}
      height={demoImg.height}
      alt="demo"
    />
  );
}
轻量备选方案(无需修改webpack配置)

如果不想调整webpack编译逻辑,可以通过预执行脚本扫描图片目录生成尺寸映射文件,实现编译阶段拿尺寸的效果:

  1. 在项目根目录新建gen-image-size.js脚本:
const fs = require('fs');
const path = require('path');
const sizeOf = require('image-size');

const imageRoot = path.resolve(__dirname, 'src/assets/images');
const sizeMap = {};

function scanDirectory(dir) {
  const fileList = fs.readdirSync(dir);
  fileList.forEach(file => {
    const fullPath = path.join(dir, file);
    const stat = fs.statSync(fullPath);
    if (stat.isDirectory()) {
      scanDirectory(fullPath);
    } else if (/\.(png|jpe?g|gif|webp)$/i.test(file)) {
      const { width, height } = sizeOf(fullPath);
      const relPath = path.relative(__dirname, fullPath).replace(/\\/g, '/');
      sizeMap[relPath] = { width, height };
    }
  });
}

scanDirectory(imageRoot);
fs.writeFileSync(
  path.resolve(__dirname, 'src/image-size-map.json'),
  JSON.stringify(sizeMap, null, 2)
);
  1. 在package.json中添加预执行钩子,保证启动、构建前自动更新尺寸映射:
{
  "scripts": {
    "prestart": "node gen-image-size.js",
    "prebuild": "node gen-image-size.js",
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test"
  }
}
  1. 组件中结合映射使用:
import demoImg from './assets/images/demo.png';
import sizeMap from './image-size-map.json';

const { width, height } = sizeMap['src/assets/images/demo.png'];

function App() {
  return <img src={demoImg} width={width} height={height} alt="demo" />;
}

若项目配置了非根路径的publicPath,只需调整脚本中路径拼接逻辑即可适配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:48:18