Next.js 14页面路由使用next/image加载public图片报错
Next.js 14页面路由中next/image无法加载public目录图片的问题
问题背景
从Next.js v12迁移至v14的页面路由项目(基于React 18.2),出现以下异常:
- 使用
next/image组件加载public目录下的图片时失败,报错信息:upstream image response failed for /_next/static/media/tata-logo.f365d74f.png - 改用原生HTML
<img>标签可正常显示目标图片 - 已尝试静态导入图片路径的方式,问题未解决
相关代码
组件代码
import tenantLogo from 'public/tenants/base/icons/tata-logo.png'; // ... <Image src={tenantLogo} alt={t('common:alt.logo')} width={getLogoWidth()} height={getLogoHeight()} objectFit="contain" />
next.config.js配置
// This file sets a custom webpack configuration to use your Next.js app // with Sentry. // https://nextjs.org/docs/api-reference/next.config.js/introduction // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ // eslint-disable-next-line @typescript-eslint/no-var-requires const { withSentryConfig } = require('@sentry/nextjs'); /* eslint-disable @typescript-eslint/no-var-requires */ const { i18n } = require('./next-i18next.config'); const withReactSvg = require('next-react-svg'); const path = require('path'); const withPWA = require('next-pwa'); const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); /** * @type {import('next').NextConfig} */ const defaultConfig = { swcMinify: true, include: path.resolve(__dirname, 'public/icons'), webpack(config) { return config; }, images: { remotePatterns: [ { protocol: 'https', hostname: '**', }, ], }, i18n, eslint: { ignoreDuringBuilds: true, // CI runs linting before build }, typescript: { ignoreBuildErrors: true, // CI runs type-checking before build }, reactStrictMode: true, publicRuntimeConfig: { appEnv: process.env.NEXT_PUBLIC_APP_ENV, clientTenantSecrets: process.env.NEXT_PUBLIC_CLIENT_TENANT_SECRETS, }, serverRuntimeConfig: { tenantSecrets: process.env.TENANT_SECRETS, }, sentry: { hideSourcemaps: true, }, }; const hocs = [ { hoc: withPWA, props: { pwa: { dest: 'public', disable: process.env.NODE_ENV === 'development', register: true, sw: 'service-worker.js', mode: 'production', }, }, }, { hoc: withReactSvg, props: {}, }, { hoc: withBundleAnalyzer, props: {}, }, ]; const configWithHocs = hocs.reduce( (accumulator, hocConfig) => hocConfig.hoc({ ...accumulator, ...hocConfig.props }), defaultConfig, ); module.exports = withSentryConfig( configWithHocs, { silent: true, authToken: process.env.NEXT_PUBLIC_SENTRY_AUTH_TOKEN, }, { hideSourcemaps: true }, );
解决方案
1. 排查插件冲突(优先检查withReactSvg)
你的withReactSvg插件配置了include: path.resolve(__dirname, 'public/icons'),但目标图片位于public/tenants目录下,该插件可能修改了webpack对静态资源的处理规则,导致png图片的打包逻辑异常:
- 临时移除
withReactSvg插件,重新启动项目验证图片是否正常加载。 - 若恢复正常,说明该插件与Next.js 14的图片处理逻辑冲突,可尝试升级插件版本,或调整插件的include范围,避免影响非svg资源。
2. 修正images配置中的remotePatterns
当前remotePatterns使用**作为hostname,会过度匹配所有请求,可能干扰本地静态图片的处理:
images: { remotePatterns: [ { protocol: 'https', hostname: '*', // 替换**为*,缩小匹配范围 }, ], unoptimized: false, // 确保开启图片优化(静态导入默认依赖此配置) },
3. 修复webpack图片处理规则
手动添加图片文件的webpack处理规则,确保静态导入的png文件被正确打包:
webpack(config) { // 新增图片资源处理规则 config.module.rules.push({ test: /\.(png|jpe?g|gif|webp)$/i, type: 'asset/resource', generator: { filename: 'static/media/[name].[hash][ext]', }, }); return config; },
4. 验证构建后的资源路径
检查生产构建后的_next/static/media目录,确认tata-logo.f365d74f.png文件是否存在:
- 如果文件不存在,说明静态导入的图片未被正确打包,大概率是插件冲突导致,逐一禁用withPWA、withBundleAnalyzer等插件排查。
5. 尝试非静态导入方式
若静态导入仍有问题,可改用路径字符串直接传入,并确保images配置允许本地路径:
// next.config.js中补充本地域名(开发环境) images: { domains: ['localhost'], remotePatterns: [/* 原有远程配置 */], },
组件中修改为:
<Image src="/tenants/base/icons/tata-logo.png" alt={t('common:alt.logo')} width={getLogoWidth()} height={getLogoHeight()} objectFit="contain" />
内容的提问来源于stack exchange,提问作者Emilis
相关产品推荐
相关产品推荐

