Next.js中使用SVG作为组件出现类型无效报错的解决方法
如何修复Next.js中SVG作为组件使用时的"type is invalid"错误?
报错信息
使用HomeIcon SVG图标组件时触发如下错误:
[ Server ] React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
已执行的操作
- 配置
next.config.mjs:
import createNextIntlPlugin from "next-intl/plugin"; const withNextIntl = createNextIntlPlugin(); /** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config) => { // SVG // Grab the existing rule that handles SVG imports const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.(".svg") ); config.module.rules.push( // Reapply the existing rule, but only for svg imports ending in ?url { ...fileLoaderRule, test: /\.svg$/i, resourceQuery: /url/, // *.svg?url }, // Convert all other *.svg imports to React components { test: /\.svg$/i, issuer: fileLoaderRule.issuer, resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url use: [ { loader: "@svgr/webpack", options: { typescript: true, ext: "tsx", }, }, ], } ); // Modify the file loader rule to ignore *.svg, since we have it handled now. fileLoaderRule.exclude = /\.svg$/i; return config; }, }; export default withNextIntl(nextConfig);
- 在根目录创建
svg.d.ts类型定义文件:
declare module "*.svg" { import React from "react"; const SVG: React.VFC<React.SVGProps<SVGSVGElement>>; export default SVG; }
- 在
tsconfig.json中添加该类型文件:
"include": [ "svg.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "next.config.mjs" ],
- 在Layout组件中使用SVG组件:
import Navbar from "@/components/Navbar"; import { FC, ReactNode, SVGProps } from "react"; import HomeIcon from "@/assets/home.svg"; import Image from "next/image"; interface layoutProps { children: ReactNode; locale: string; } const Layout: FC<layoutProps> = ({ children, locale }) => { return ( <div> <Navbar locale={locale} /> {children} <div className="px-7 bg-white shadow-lg rounded-2xl fixed bottom-0 right-0 left-0 border border-green-600"> <div className="flex"> <div className="flex-1 group"> <a href="#" className="flex items-end justify-center text-center mx-auto px-4 pt-2 w-full text-gray-400 group-hover:text-green-800" > <span className="block px-1 pt-1 pb-1"> <HomeIcon className="w-6 h-6" /> <span className="block text-xs pb-2">Home</span> <span className="block w-5 mx-auto h-1 group-hover:bg-green-800 rounded-full"></span> </span> </a> </div> </div> </div> ); }; export default Layout;
修复方案
1. 重构webpack SVG处理规则
原配置修改默认fileLoaderRule的方式易引发规则冲突,建议直接移除默认SVG规则后重新定义:
import createNextIntlPlugin from "next-intl/plugin"; const withNextIntl = createNextIntlPlugin(); /** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config) => { // 移除默认的SVG处理规则 config.module.rules = config.module.rules.filter( (rule) => !rule.test?.test?.(".svg") ); // 添加SVGR规则:将不带?url后缀的SVG转为React组件 config.module.rules.push( { test: /\.svg$/i, issuer: /\.[jt]sx?$/, resourceQuery: { not: /url/ }, use: [ { loader: "@svgr/webpack", options: { typescript: true, ext: "tsx", }, }, ], }, // 保留资源加载规则:用于带?url后缀的SVG(作为静态资源导入) { test: /\.svg$/i, resourceQuery: /url/, type: "asset/resource", } ); return config; }, }; export default withNextIntl(nextConfig);
2. 验证类型定义有效性
确认svg.d.ts无语法错误,且tsconfig.json的include数组已正确包含该文件。若类型定义不生效,可尝试将文件移至src目录(若项目使用src结构),或在tsconfig中明确指定文件路径。
3. 清理缓存并重启服务
执行以下命令清除Next.js缓存与依赖缓存:
rm -rf .next node_modules npm install npm run dev
4. 检查SVG文件与导入路径
确保@/assets/home.svg文件存在,同时验证tsconfig.json中路径别名@的配置正确:
"paths": { "@/*": ["./*"] }
内容的提问来源于stack exchange,提问作者Mohammadreza Ataei
相关产品推荐
相关产品推荐

