🧩 背景介绍
在 Next.js 项目中,我们经常希望通过 @svgr/webpack
将 .svg
文件作为 React 组件 引入,像这样使用:
tsx
CopyEdit
import Logo from '@/assets/logo.svg'
export default function Header() {
return <Logo width={120} />
}
这在传统 Webpack 模式下非常常见,但在 Next.js 15 的 Turbo 模式中却无法使用,原因如下:
❌ 问题说明
现象:
在启用 Turbo 模式后(next build --turbo
),你会发现:
- 无法识别
@svgr/webpack
- 无法在
next.config.js
中添加webpack()
自定义配置 - 报错如:
vbnet
CopyEdit
TypeError: config.module.rules.push is not a function
⚠️ 原因解析:Turbo 模式基于 Rust 构建工具 Turbopack
项目 | 非 Turbo 模式 | ✅ Turbo 模式(Turbopack) |
---|---|---|
构建引擎 | Webpack + Babel | Turbopack(Rust 编写,Vercel 出品) |
插件机制 | 支持 Webpack 插件和 loader | 暂不支持 Webpack 插件或 loader |
构建配置入口 | 支持自定义 webpack(config) | 不支持自定义 Webpack 配置 |
插件兼容性 | @svgr/webpack 等广泛支持 | 不兼容所有 Webpack 插件 |
总结:Turbo 模式是全新构建系统,完全抛弃 Webpack 架构,因此所有基于 Webpack 的插件(如 @svgr/webpack)都不生效。
✅ 解决方案
根据你的需求,这里有 3 种可选解决方案:
✅ 方案一:切换为非 Turbo 模式(推荐)
如果你需要 @svgr/webpack
,请禁用 Turbo 模式,恢复传统构建方式。
📌 步骤:
- 编辑
next.config.js
:
js
CopyEdit
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack'],
})
return config
},
}
module.exports = nextConfig
- 添加
svg.d.ts
(如果使用 TypeScript):
ts
CopyEdit
// types/svg.d.ts
declare module '*.svg' {
import * as React from 'react'
const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>
export default ReactComponent
}
- 安装依赖:
bash
CopyEdit
npm install --save-dev @svgr/webpack
- 使用方式:
tsx
CopyEdit
import Logo from '@/assets/logo.svg'
export default function Page() {
return <Logo width={100} />
}
- 构建时 **不要加 **
**--turbo**
:
bash
CopyEdit
npm run build ✅ 正确
npm run build --turbo ❌ 错误
🚧 方案二:使用 <img src="/xxx.svg" />
代替(兼容 Turbo 模式)
如果你愿意不将 .svg
当作组件处理,可以将 SVG 放在 public/
文件夹下,用原生 <img />
标签引入:
tsx
CopyEdit
export default function Page() {
return <img src="/logo.svg" alt="Logo" width={100} />
}
适合简单展示场景,但不支持 fill
/stroke
等 React 属性控制。
🛠️ 方案三:封装 SVG 动态加载组件(仅适合部分情况)
你可以封装一个 SvgIcon
组件,通过 require
加载 SVG 文件:
tsx
CopyEdit
// components/SvgIcon.tsx
'use client'
export function SvgIcon({ name, ...props }: { name: string } & React.SVGProps<SVGSVGElement>) {
const Icon = require(`../public/${name}.svg`).default
return <Icon {...props} />
}
// 用法
<SvgIcon name="logo" width={100} />
⚠️ 缺点:本质还是在使用 public/
下文件,不是真正组件形式,存在兼容性问题。
📌 总结推荐
需求 | 推荐方案 |
---|---|
需要使用 SVG 组件(如控制颜色) | ✅ 非 Turbo 模式 |
简单展示 SVG 图标 | <img src="/..." /> |
想尝试 Turbo 模式 | 暂时避免使用 @svgr/webpack |