无法将 SVG 导入 Next.js
Can't import SVG into Next.js
当我尝试导入 SVG 图像时,出现以下错误。我必须使用哪个加载器来导入 SVG 图像?
./static/Rolling-1s-200px.svg 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000"><filter id="b"><feGaussianBlur stdDeviation="12" /></filter><path fill="#817c70" d="M0 0h2000v2000H0z"/><g filter="url(#b)" transform="translate(4 4) scale(7.8125)" fill-opacity=".5"><ellipse fill="#000210" rx="1" ry="1" transform="matrix(50.41098 -3.7951 11.14787 148.07886 107 194.6)"/><ellipse fill="#eee3bb" rx="1" ry="1" transform="matrix(-56.38179 17.684 -24.48514 -78.06584 205 110.1)"/><ellipse fill="#fff4bd" rx="1" ry="1" transform="matrix(35.40604 -5.49219 14.85017 95.73337 16.4 123.6)"/><ellipse fill="#79c7db" cx="21" cy="39" rx="65" ry="65"/><ellipse fill="#0c1320" cx="117" cy="38" rx="34" ry="47"/><ellipse fill="#5cb0cd" rx="1" ry="1" transform="matrix(-39.46201 77.24476 -54.56092 -27.87353 219.2 7.9)"/><path fill="#e57339" d="M271 159l-123-16 43 128z"/><ellipse fill="#47332f" cx="214" cy="237" rx="242" ry="19"/></g></svg>
您需要提供一个 webpack 加载程序来处理 SVG 导入,其中一个著名的是 svgr。
为了将其配置为与 next 一起使用,您需要将加载程序的用法添加到 next.config.js
文件中,如下所示:
// next.config.js
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
issuer: {
test: /\.(js|ts)x?$/,
// for webpack 5 use
// { and: [/\.(js|ts)x?$/] }
},
use: ['@svgr/webpack'],
});
return config;
},
};
有关更多配置信息,check out the docs。
别忘了先安装@svgr/webpack
:
$ npm install --save-dev @svgr/webpack
编辑
我添加了一个 issuer
部分,该部分将这些 svg 严格限制为仅适用于从 js / ts
文件导入的 svg 的组件。
这允许您为从其他文件类型(例如 .css
)导入的 svg
s 配置其他行为
安装next-images.
yarn add -D next-images
在您的项目中创建一个 next.config.js
// next.config.js
const withImages = require('next-images')
module.exports = withImages()
这对我有用,没有任何其他依赖性
// In next.config.js
module.exports = {
webpack (config, options) {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000
}
}
});
return config;
}
};
您可以使用babel-plugin-inline-react-svg
import React from 'react';
import CloseSVG from './close.svg';
const MyComponent = () => <CloseSVG />;
npm install --save-dev babel-plugin-inline-react-svg
// .babelrc
{
"plugins": [
"inline-react-svg"
]
}
或参阅 link 了解更多说明。
我个人更喜欢 next-react-svg 插件,它允许将 SVG 图像视为 React 组件并自动内联它们,类似于 Create React App 所做的。
使用方法如下:
- 安装
next-react-svg
:
npm i next-react-svg
- 将必要的设置添加到
next.config.js
:
const withReactSvg = require('next-react-svg')
const path = require('path')
module.exports = withReactSvg({
include: path.resolve(__dirname, 'src/assets/svg'),
webpack(config, options) {
return config
}
})
include
参数是必需的,它指向您的 SVG 图像文件夹。
如果您已经为您的 Next.js 启用了任何插件,请考虑使用 next-compose-plugins 来正确组合它们。
- 将您的 SVG 作为普通 React 组件导入:
import Logo from 'assets/svg/Logo.svg';
export default () => (
<Logo />
);
就是这样。从现在开始,Next.js 将以这种方式将 SVG 图像作为 SVG 标签导入到呈现的标记中。
您只需通过 <img>
标签导入即可。
<img src='./next.svg' alt='next' />
只需确保 svg 在 public 文件夹中。
您可以使用 next-plugin-svgr
和 next-compose-plugins
清理插件(如果您有):
// next.config.js
const withPlugins = require("next-compose-plugins");
const withSvgr = require("next-svgr");
module.exports = withPlugins([
withSvgr
// your other plugins here
]);
或 next-plugin-svgr
:
// next.config.js
const withSvgr = require('next-plugin-svgr');
module.exports = withSvgr({
webpack(config, options) {
return config;
},
});
快捷方式:<img>
或<Image>
Not suitable for interactive SVGs or if you intend to manipulate a SVG by external CSS/JS
可以用官方next/image
component or img
tag (as mentioned in this ).
您只需将 svg
文件从 static
移动到 public
,然后执行如下操作:
import Image from 'next/image';
// ...
<Image src="/Rolling-1s-200px.svg" width="2000" height="2000" />
但是通过使用这种方法,svg
文件的内容将不会直接出现在响应中;浏览器将获得一个 <img src="..." ...></img>
标签。
还需要指定width
和height
,但可以从viewbox
属性中计算出来。
在 Next.js v11 及更高版本上,您还可以:
import Image from 'next/image';
import Illustration from '../static/Rolling-1s-200px.svg';
// ...
<Image src={Illustration} />
// one needs to use `Illustration.src` to get the source URL
// <img src={Illustration.src} ... />
在内部包含 SVG HTML(对于 webpack-5、TS)
has shown how to do this with webpack-4
, but since webpack-5
is now default, I'm sharing the appropriate config. You can use it after installing @svgr/webpack
(yarn add -D @svgr/webpack
或npm install @svgr/webpack --save-dev
):
// next.config.js
// https://github.com/gregberge/svgr/issues/551#issuecomment-839772396
module.exports = {
// other configs...
// future: { webpack5: true }, // -- not needed since Next.js v11.0.0
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: { and: [/\.(js|ts|md)x?$/] },
use: [
{
loader: '@svgr/webpack',
options: {
prettier: false,
svgo: true,
svgoConfig: { plugins: [{ removeViewBox: false }] },
titleProp: true,
},
},
],
});
return config;
},
};
如果你没有使用 options
作为加载程序,那么你可以简单地写成这样:
use: ['@svgr/webpack']
如果您使用的是 @svgr/webpack
的 v6,那么您需要像这样指定 SVGO 配置:
// ...
plugins: [
{
name: 'preset-default',
params: {
overrides: { removeViewBox: false },
},
},
],
// ...
如果使用打字稿,您需要定义适当的模块(在您导入的目录中 svg
,或者可能将其作为 <some-name>.d.ts
添加到根目录并包含它 tsconfig
):
// index.d.ts
declare module '*.svg' {
const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
export default ReactComponent;
}
那么你可以这样使用它:
import Illustration from '../static/Rolling-1s-200px.svg';
// ...
<Illustration />
注意:Next.js v11.0.1+ 已将 SVG 声明为模块导出 any
。您的自定义配置不会覆盖 next-env.d.ts
设置的类型,除非您排除后者。请参考.
[已过时(Fixed)] 更新:
如果您使用的是 Next.js v11.0.0,那么您在导入 SVG 时可能会遇到错误。请更新至 v11.0.1
或以上。 请遵循 this comment 中提到的解决方法。
另一种不安装任何库的解决方案
import React from "react";
export default function GoogleLogo() {
return (
<svg className="svgIcon-use" width="25" height="37" viewBox="0 0 25 25">
<g fill="none" fillRule="evenodd">
<path
d="M20.66 12.693c0-.603-.054-1.182-.155-1.738H12.5v3.287h4.575a3.91 3.91 0 0 1-1.697 2.566v2.133h2.747c1.608-1.48 2.535-3.65 2.535-6.24z"
fill="#4285F4"
/>
<path
d="M12.5 21c2.295 0 4.22-.76 5.625-2.06l-2.747-2.132c-.76.51-1.734.81-2.878.81-2.214 0-4.088-1.494-4.756-3.503h-2.84v2.202A8.498 8.498 0 0 0 12.5 21z"
fill="#34A853"
/>
<path
d="M7.744 14.115c-.17-.51-.267-1.055-.267-1.615s.097-1.105.267-1.615V8.683h-2.84A8.488 8.488 0 0 0 4 12.5c0 1.372.328 2.67.904 3.817l2.84-2.202z"
fill="#FBBC05"
/>
<path
d="M12.5 7.38c1.248 0 2.368.43 3.25 1.272l2.437-2.438C16.715 4.842 14.79 4 12.5 4a8.497 8.497 0 0 0-7.596 4.683l2.84 2.202c.668-2.01 2.542-3.504 4.756-3.504z"
fill="#EA4335"
/>
</g>
</svg>
);
}
并使用:
import GoogleLogo from "./GoogleLogo";
class Login extends React.Component {
render() {
return (
<LoginLayout title="Login Page">
<div>
<Link href="/auth/google">
<a className="button">
<div>
<span className="svgIcon t-popup-svg">
<GoogleLogo />
</span>
</div>
</a>
</Link>
</div>
</LoginLayout>
);
}
}
我尝试了第一个答案,但出现错误,所以这个有效:
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ["@svgr/webpack"]
});
return config;
}};
Next.js 12.0.9
和 Webpack 5
这对我有用:
yarn add --dev url-loader @svgr/webpack
// next.config.js
module.exports = {
webpack(config, options) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
});
return config;
},
};
如果您想在代码中使用 SVG 文件无需任何配置或安装依赖项并且完全控制标签的属性,最好的解决办法是将SVG文件转换为JSX或TSX组件。
JSX解决方案:
export const YourSVg = ({color, width, height}) => (
<svg fill={color} height={height} width={width}>
..rest of the svg tags...
</svg>
)
TSX解决方案:
export const YourSVg:React.FC<{color:string, width:string, height:string}> =
({color, width, height}) => (
<svg color={color} height={height} width={width}>
..rest of the svg tags...
</svg>
)
如何使用?
可以像普通组件一样导入并像以前一样使用
例如:
import YourSVg from '../from the path/path
<YourSVg color='red' width='10px' height='10px/>
当我尝试导入 SVG 图像时,出现以下错误。我必须使用哪个加载器来导入 SVG 图像?
./static/Rolling-1s-200px.svg 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000"><filter id="b"><feGaussianBlur stdDeviation="12" /></filter><path fill="#817c70" d="M0 0h2000v2000H0z"/><g filter="url(#b)" transform="translate(4 4) scale(7.8125)" fill-opacity=".5"><ellipse fill="#000210" rx="1" ry="1" transform="matrix(50.41098 -3.7951 11.14787 148.07886 107 194.6)"/><ellipse fill="#eee3bb" rx="1" ry="1" transform="matrix(-56.38179 17.684 -24.48514 -78.06584 205 110.1)"/><ellipse fill="#fff4bd" rx="1" ry="1" transform="matrix(35.40604 -5.49219 14.85017 95.73337 16.4 123.6)"/><ellipse fill="#79c7db" cx="21" cy="39" rx="65" ry="65"/><ellipse fill="#0c1320" cx="117" cy="38" rx="34" ry="47"/><ellipse fill="#5cb0cd" rx="1" ry="1" transform="matrix(-39.46201 77.24476 -54.56092 -27.87353 219.2 7.9)"/><path fill="#e57339" d="M271 159l-123-16 43 128z"/><ellipse fill="#47332f" cx="214" cy="237" rx="242" ry="19"/></g></svg>
您需要提供一个 webpack 加载程序来处理 SVG 导入,其中一个著名的是 svgr。
为了将其配置为与 next 一起使用,您需要将加载程序的用法添加到 next.config.js
文件中,如下所示:
// next.config.js
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
issuer: {
test: /\.(js|ts)x?$/,
// for webpack 5 use
// { and: [/\.(js|ts)x?$/] }
},
use: ['@svgr/webpack'],
});
return config;
},
};
有关更多配置信息,check out the docs。
别忘了先安装@svgr/webpack
:
$ npm install --save-dev @svgr/webpack
编辑
我添加了一个 issuer
部分,该部分将这些 svg 严格限制为仅适用于从 js / ts
文件导入的 svg 的组件。
这允许您为从其他文件类型(例如 .css
)导入的 svg
s 配置其他行为
安装next-images.
yarn add -D next-images
在您的项目中创建一个 next.config.js
// next.config.js
const withImages = require('next-images')
module.exports = withImages()
这对我有用,没有任何其他依赖性
// In next.config.js
module.exports = {
webpack (config, options) {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000
}
}
});
return config;
}
};
您可以使用babel-plugin-inline-react-svg
import React from 'react';
import CloseSVG from './close.svg';
const MyComponent = () => <CloseSVG />;
npm install --save-dev babel-plugin-inline-react-svg
// .babelrc
{
"plugins": [
"inline-react-svg"
]
}
或参阅 link 了解更多说明。
我个人更喜欢 next-react-svg 插件,它允许将 SVG 图像视为 React 组件并自动内联它们,类似于 Create React App 所做的。
使用方法如下:
- 安装
next-react-svg
:
npm i next-react-svg
- 将必要的设置添加到
next.config.js
:
const withReactSvg = require('next-react-svg')
const path = require('path')
module.exports = withReactSvg({
include: path.resolve(__dirname, 'src/assets/svg'),
webpack(config, options) {
return config
}
})
include
参数是必需的,它指向您的 SVG 图像文件夹。
如果您已经为您的 Next.js 启用了任何插件,请考虑使用 next-compose-plugins 来正确组合它们。
- 将您的 SVG 作为普通 React 组件导入:
import Logo from 'assets/svg/Logo.svg';
export default () => (
<Logo />
);
就是这样。从现在开始,Next.js 将以这种方式将 SVG 图像作为 SVG 标签导入到呈现的标记中。
您只需通过 <img>
标签导入即可。
<img src='./next.svg' alt='next' />
只需确保 svg 在 public 文件夹中。
您可以使用 next-plugin-svgr
和 next-compose-plugins
清理插件(如果您有):
// next.config.js
const withPlugins = require("next-compose-plugins");
const withSvgr = require("next-svgr");
module.exports = withPlugins([
withSvgr
// your other plugins here
]);
或 next-plugin-svgr
:
// next.config.js
const withSvgr = require('next-plugin-svgr');
module.exports = withSvgr({
webpack(config, options) {
return config;
},
});
快捷方式:<img>
或<Image>
Not suitable for interactive SVGs or if you intend to manipulate a SVG by external CSS/JS
可以用官方next/image
component or img
tag (as mentioned in this
您只需将 svg
文件从 static
移动到 public
,然后执行如下操作:
import Image from 'next/image';
// ...
<Image src="/Rolling-1s-200px.svg" width="2000" height="2000" />
但是通过使用这种方法,svg
文件的内容将不会直接出现在响应中;浏览器将获得一个 <img src="..." ...></img>
标签。
还需要指定width
和height
,但可以从viewbox
属性中计算出来。
在 Next.js v11 及更高版本上,您还可以:
import Image from 'next/image';
import Illustration from '../static/Rolling-1s-200px.svg';
// ...
<Image src={Illustration} />
// one needs to use `Illustration.src` to get the source URL
// <img src={Illustration.src} ... />
在内部包含 SVG HTML(对于 webpack-5、TS)
webpack-4
, but since webpack-5
is now default, I'm sharing the appropriate config. You can use it after installing @svgr/webpack
(yarn add -D @svgr/webpack
或npm install @svgr/webpack --save-dev
):
// next.config.js
// https://github.com/gregberge/svgr/issues/551#issuecomment-839772396
module.exports = {
// other configs...
// future: { webpack5: true }, // -- not needed since Next.js v11.0.0
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: { and: [/\.(js|ts|md)x?$/] },
use: [
{
loader: '@svgr/webpack',
options: {
prettier: false,
svgo: true,
svgoConfig: { plugins: [{ removeViewBox: false }] },
titleProp: true,
},
},
],
});
return config;
},
};
如果你没有使用 options
作为加载程序,那么你可以简单地写成这样:
use: ['@svgr/webpack']
如果您使用的是 @svgr/webpack
的 v6,那么您需要像这样指定 SVGO 配置:
// ...
plugins: [
{
name: 'preset-default',
params: {
overrides: { removeViewBox: false },
},
},
],
// ...
如果使用打字稿,您需要定义适当的模块(在您导入的目录中 svg
,或者可能将其作为 <some-name>.d.ts
添加到根目录并包含它 tsconfig
):
// index.d.ts
declare module '*.svg' {
const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
export default ReactComponent;
}
那么你可以这样使用它:
import Illustration from '../static/Rolling-1s-200px.svg';
// ...
<Illustration />
注意:Next.js v11.0.1+ 已将 SVG 声明为模块导出 any
。您的自定义配置不会覆盖 next-env.d.ts
设置的类型,除非您排除后者。请参考
[已过时(Fixed)] 更新:
如果您使用的是 Next.js v11.0.0,那么您在导入 SVG 时可能会遇到错误。请更新至 v11.0.1
或以上。 请遵循 this comment 中提到的解决方法。
另一种不安装任何库的解决方案
import React from "react";
export default function GoogleLogo() {
return (
<svg className="svgIcon-use" width="25" height="37" viewBox="0 0 25 25">
<g fill="none" fillRule="evenodd">
<path
d="M20.66 12.693c0-.603-.054-1.182-.155-1.738H12.5v3.287h4.575a3.91 3.91 0 0 1-1.697 2.566v2.133h2.747c1.608-1.48 2.535-3.65 2.535-6.24z"
fill="#4285F4"
/>
<path
d="M12.5 21c2.295 0 4.22-.76 5.625-2.06l-2.747-2.132c-.76.51-1.734.81-2.878.81-2.214 0-4.088-1.494-4.756-3.503h-2.84v2.202A8.498 8.498 0 0 0 12.5 21z"
fill="#34A853"
/>
<path
d="M7.744 14.115c-.17-.51-.267-1.055-.267-1.615s.097-1.105.267-1.615V8.683h-2.84A8.488 8.488 0 0 0 4 12.5c0 1.372.328 2.67.904 3.817l2.84-2.202z"
fill="#FBBC05"
/>
<path
d="M12.5 7.38c1.248 0 2.368.43 3.25 1.272l2.437-2.438C16.715 4.842 14.79 4 12.5 4a8.497 8.497 0 0 0-7.596 4.683l2.84 2.202c.668-2.01 2.542-3.504 4.756-3.504z"
fill="#EA4335"
/>
</g>
</svg>
);
}
并使用:
import GoogleLogo from "./GoogleLogo";
class Login extends React.Component {
render() {
return (
<LoginLayout title="Login Page">
<div>
<Link href="/auth/google">
<a className="button">
<div>
<span className="svgIcon t-popup-svg">
<GoogleLogo />
</span>
</div>
</a>
</Link>
</div>
</LoginLayout>
);
}
}
我尝试了第一个答案,但出现错误,所以这个有效:
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ["@svgr/webpack"]
});
return config;
}};
Next.js 12.0.9
和 Webpack 5
这对我有用:
yarn add --dev url-loader @svgr/webpack
// next.config.js
module.exports = {
webpack(config, options) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
});
return config;
},
};
如果您想在代码中使用 SVG 文件无需任何配置或安装依赖项并且完全控制标签的属性,最好的解决办法是将SVG文件转换为JSX或TSX组件。
JSX解决方案:
export const YourSVg = ({color, width, height}) => (
<svg fill={color} height={height} width={width}>
..rest of the svg tags...
</svg>
)
TSX解决方案:
export const YourSVg:React.FC<{color:string, width:string, height:string}> =
({color, width, height}) => (
<svg color={color} height={height} width={width}>
..rest of the svg tags...
</svg>
)
如何使用?
可以像普通组件一样导入并像以前一样使用
例如:
import YourSVg from '../from the path/path
<YourSVg color='red' width='10px' height='10px/>