无法将 SVG 导入 Next.js

IT技术 reactjs webpack-4 next.js
2021-04-13 08:48:48

当我尝试导入 SVG Image 时,会显示以下错误。我必须使用哪个加载程序来导入 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>
6个回答

你需要提供一个 webpack 加载器来处理 SVG 导入,其中一个著名的就是svgr

为了配置它以供下一步使用,您需要将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;
  },
};

有关更多配置信息,请查看文档

不要忘记先安装@svgr/webpack

$ npm install --save-dev @svgr/webpack

编辑

我添加了一个issuer部分,将这些 svg 严格为组件,仅适用于从js / ts文件导入的 svg 这允许您为svg从其他文件类型(例如.css导入的 s配置其他行为

对于 webpack5,使用 issuer: { and: [/\.(js|ts)x?$/] }
2021-06-11 08:48:48
next-svgr是一个更高级别的 Next 插件,实现了相同的解决方案。不过,它目前不支持issuer参数。
2021-06-15 08:48:48
是的,这不是 bueno @felixmosh
2021-06-15 08:48:48

安装next-images

yarn add -D next-images

在你的项目中创建一个 next.config.js

// next.config.js
const withImages = require('next-images')
module.exports = withImages()
对于那些使用 Typescript 的人,不要忘记添加: /// <reference types="next-images" /> 到你的 next-env.d.ts 文件中。
2021-06-20 08:48:48

快速方法:<img><Image>

不适合交互式 SVG,或者如果您打算通过外部 CSS/JS 操作 SVG

可以使用官方next/image组件或img标签(如本答案所述)。

您只需要将svg文件移动public而不是static,然后执行以下操作:

import Image from 'next/image';

// ...

<Image src="/Rolling-1s-200px.svg" width="2000" height="2000" />

但是使用这种方法,svg文件的内容不会直接出现在响应中;浏览器会得到一个<img src="..." ...></img>标签。

还需要指定widthand height,但您可以从viewbox属性中计算它

在 Next.js v11.x 上,您还可以执行以下操作:

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} ... />

在 HTML 中包含 SVG(用于 webpack-5、TS)

接受的答案已经展示了如何使用做到这一点webpack-4,但由于webpack-5现在是默认的,我分享了适当的配置。您可以在安装@svgr/webpack(yarn add -D @svgr/webpacknpm 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']

如果您使用的是 v6 of@svgr/webpack那么您需要像这样指定 SVGO 配置:

// ...

plugins: [
  {
    name: 'preset-default',
    params: {
      overrides: { removeViewBox: false },
    },
  },
],

// ...

如果使用typescript,您需要定义适当的module(在您导入的目录中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 声明为module导出any您的自定义配置不会覆盖设置的类型,next-env.d.ts除非您排除后者。请参考这个

[过时(已修复 ]更新:

如果您使用 Next.js v11.0.0,那么您在导入 SVG 时可能会遇到错误。请更新至v11.0.1或以上。请遵循此评论中提到的解决方法

@deadcoder0904 请参考答案的第一部分。将您的 SVG 移动到public并像这样使用它们<Image src="/svg-name.svg" height="100" width="100" />您也可以将您的资产文件夹直接移动到public目录;那么你需要通过srcas /assets/svg-name.svg
2021-05-28 08:48:48
我可以.svgpublic/目录中使用吗?目前,我创建assets/只是为了使用 TS 之类的相对导入,但我只想@/assets/logo.svg使用它public/是否可以?
2021-06-11 08:48:48
@deadcoder0904 您可以使用这样的路径:"@/*": ["src/*", "public/*"]然后import Logo from '@/Logo.svg';会起作用。
2021-06-12 08:48:48
@deadcoder0904 那是不可能的。我的意思是您可以将 SVG 保存在public或任何文件夹中,但您需要@/public/logo.svg在导入时指定整个路径答案的第二部分显示了这一点。您不必Image在其中使用组件。
2021-06-16 08:48:48
注意:assets只是一个约定俗成的文件夹名,Next.js 本身并不理解。如果您想将资产放在public目录本身中,那也可以;您只需要更改导入语句:import Logo from '@/public/logo.svg';但请记住,访问您站点的任何人都可以访问公共文件夹,因此不要在那里放置任何机密信息。
2021-06-16 08:48:48

我个人更喜欢next-react-svg插件,它允许将 SVG 图像视为 React 组件并自动内联它们,类似于 Create React App 所做的。

以下是如何使用它:

  1. 安装next-react-svg
npm i next-react-svg
  1. 将必要的设置添加到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来正确组合它们。

  1. 将您的 SVG 导入为普通的 React 组件:
import Logo from 'assets/svg/Logo.svg';

export default () => (
  <Logo />
);

而已。从现在开始,Next.js 将把以这种方式导入的 SVG 图像作为 SVG 标签包含在渲染标记中。

这是非常感谢。如果您像我一样来自 Create React App,请确保更改您的 SVG 导入语句。即改变import { ReactComponent as MySvg } from 'src/assets/mysvg.svg'import MySvg from 'src/assets/mysvg.svg'
2021-05-25 08:48:48
你知道如何在 storybook 中使用 next-react-svg 吗?
2021-06-17 08:48:48

你可以使用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"
  ]
}

或查看链接以获取更多说明。

1. 不支持绝对路径 2. 您必须手动设置视图框,因为此插件不会从 svg 文件中导入它 3. 不适用于typescript。没有简单的解决办法吗??Nextjs 存在多年,这个问题是在 2019 年问的!
2021-06-04 08:48:48
无论出于何种原因,这都不适用于 Typescript 项目。
2021-06-09 08:48:48