如何使用Webpack设置内联SVG

59

我想知道如何使用webpack设置内联SVG?

我正在按照react-webpack-cookbook的指导进行操作。

我的webpack.config已正确设置了文件加载器(file loader)

然而,示例展示了如何使用背景图片:

.icon {
   background-image: url(./logo.svg);
}

这个方法很好用,但我想要一个内联的svg图像,我该如何在我的React组件中嵌入我的logo.svg呢?

import React, { Component } from 'react'

class Header extends Component {

  render() {
    return (
        <div className='header'>
            <img src={'./logo.svg'} />
        </div>
    );
  }
};

export default Header
9个回答

37

这里有一个简单的非React解决方案。

  1. 安装 Svg inline loader
  2. 在webpack.config.js中添加{ test: /\.svg$/, loader: 'svg-inline-loader' }
  3. 在您的js文件中导入svg图像,并将其添加到DOM元素中,例如:
  import Svg from './svg.svg';

  function component() {
    const element = document.createElement('div');

    element.innerHTML = Svg;

    return element;
  }

  document.body.appendChild(component());

18
感谢不依赖React并呈现出原生的ECMAScript。 - ipatch

36

实际上,Michelle的答案给了我正确的方向,并且在webpack中加载svg文件并将其用作<img>的来源非常有效。

然而,为了实际获取内联svg,我需要执行以下操作:

使用svg-inline-loader替代file-loader作为您的svg加载器:

{ test: /\.svg$/, loader: 'svg-inline-loader' }

然后在组件中内联加载svg:

import React, { Component } from 'react'
import logo from "./logo.svg";

class Header extends Component {

  render() {
    return (
        <div className='header'>
          <span dangerouslySetInnerHTML={{__html: logo}} />
        </div>
    );
  }
};

export default Header

看起来有一个用于React的内联SVG封装器 svg-inline-react,这将是另一种选项,而不是使用 <div dangerouslySetInnerHTML={{__html: mySvg}} />


2
仅供参考,这与服务器渲染完全不兼容...因此并不像我曾经想象的那样有用。我已经重新使用svg作为背景图像。它似乎也会像内联svg一样使JavaScript捆绑包膨胀,当然这取决于svg的优化程度。 - svnm
5
Twitter发布了一个很好的案例研究,说明为什么你不应该使用'dangerouslySetInnerHTML'来显示SVG:https://medium.com/@paularmstrong/twitter-lite-and-high-performance-react-progressive-web-apps-at-scale-d28a00e780a3#3732 - uwolfer

31

我希望我的迟来的回答仍对某人有用,因为我不喜欢上述任何选项。

react-svg-loader webpack加载器允许您像JSX组件一样导入SVG图标:

import Logo from './logo.svg';

class App extends Component {
  render() {
    return (
      <div className="App">
          <Logo fill="red" className="logo" width={50} height={50} />
      </div>
    );
  }
}

最小配置如下:

{
  test: /\.svg$/,
  use: [
    {
      loader: "babel-loader"
    },
    {
      loader: "react-svg-loader",
      options: {
        jsx: true // true outputs JSX tags
      }
    }
  ]
}

最好的部分是它只输出SVG文件内容,没有任何额外的包装器和dangerouslySetInnerHTML在您的代码中。


这在最新的React 16.10和Webpack 4.41上完美运行。谢谢! - Greg

21

虽然这个问题旧了,但我没有在任何地方看到这种解决方案,所以决定发布它,希望能帮助到某些人。

如果您想要对那些SVG图标进行样式设置,您可能需要使用原始加载程序(raw loader)来加载它们:

webpack.config.js:

 { 
      test: /\.svg$/, 
      loader: 'raw-loader' 
 } 

我个人的看法是:

import closeIcon from 'svg/ic_close_black_24px.svg'; 

模板(Mustache使用三个大括号插入未编码的SVG数据(URL)):

<button id="closeModal">
  {{{closeIcon}}}
</button>
这样,SVG数据将被插入而不是括号,并且看起来像这样:
<button id="closeModal">
  <svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
    <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
    <path d="M0 0h24v24H0z" fill="none"></path>
  </svg>
</button>

我正在使用Backbone与Mustache模板引擎以及Webpack 2.5.1。


1
打算使用基于字符串模板的库,如backbone + mustache或vue进行工作,但不使用react,因为它使用JSX而不是原始字符串。虽然可能可以使用“dangerouslySetInnerHTML”... - user2927940

12

如果我没记错的话,因为你使用了文件加载器,你可以像使用其他任何require一样利用它。Webpack会将require("./logo.svg")转换为一个文件路径,并在打包时发出。

import React, { Component } from 'react'

import mySvg from './logo.svg'

class Header extends Component {

  render() {
    return (
        <div className='header'>
            <img src={mySvg} />
        </div>
    );
  }
};

export default Header

5
对我来说这不起作用 :( 你能贴出你的 webpack.config.js 文件吗?也许我能在那里找到我的错误。 - Amy Pellegrini
只有在我重新启动 npm start 后才对我起作用。 - chenop
这会将SVG内联添加吗?还是它会将SVG包装在图像标记中? - ipatch

6

与另一个使用React的答案类似,还有一个方便的Vue插件。

vue-svg-loader只需将其放入您的配置中并开始使用。好处是它也会通过SVGO运行您的SVG以进行优化。

配置

{
    test: /\.svg$/,
  loader: 'vue-svg-loader', // `vue-svg` for webpack 1.x
  options: {
    // optional [svgo](https://github.com/svg/svgo) options
    svgo: {
      plugins: [
        {removeDoctype: true},
        {removeComments: true}
      ]
    }
  }
}

使用方法

<template>
  <nav id="menu">
    <a href="...">
      <SomeIcon class="icon" />
      Some page
    </a>
  </nav>
</template>

<script>
import SomeIcon from './assets/some-icon.svg';

export default {
  name: 'menu',
  components: {
    SomeIcon,
  },
};
</script>

1

@svgr/webpack (npm) 是 create-react-app 使用的内联 SVG 加载器。

将规则添加到您的 webpack 配置中:

{
  test: /\.svg$/,
  use: ['@svgr/webpack'],
}

然后你可以将svg作为React组件导入:
import Star from './star.svg'

const App = () => (
  <div>
    <Star />
  </div>
)

1

如果使用svg-inline-loader时遇到“找不到模块”错误的用户,请尝试安装babel-plugin-inline-react-svg并将其添加到babel插件中:

"plugins": [
    ...
    ["inline-react-svg", {}]
],
...

1
Angular解决方案(2019年):使用svg-sprite-loader将SVG合并为单个精灵,与Webpack捆绑包一起进行延迟加载。
Webpack
{
  test: /\.svg$/,
  use: [
    'svg-sprite-loader',
    'svgo-loader' // Optimize SVGs (optional)
  ]
}

HTML
<svg>
    <use xlink:href="#arrow"/>
</svg>

Angular组件

export * from 'assets/images/icons/arrow.svg';

我使用export(而不是import)来防止AOT编译器在摇树时删除导入,同时允许组件中的代码最小化,但如果您愿意,可以使用import
要以这种方式使用导出,您必须在package.json中配置编译器以期望从SVG文件中产生副作用(即不能使用“sideEffects”:false)。请参见Webpack Tree Shaking Guide
"sideEffects": [
    "*.svg",
],

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接