/react-svg-loader

A webpack loader that loads svg as a React Component

Primary LanguageJavaScript

react-svg-loader

Build Status npm version Code Climate Test Coverage

Versions

Current

  • v2.0.0-alpha.0 - master branch
  • Drops Node 0.12 support (use at your own risk)

v1.x

branch=v1

v0.1.x

branch=v0.1

Install

npm i react-svg-loader

Usage

// without webpack loader config
import Image1 from 'react-svg!./image1.svg';

// or if you're passing all .svg files via react-svg loader,
import Image2 from './image1.svg';

// and use it like any other React Component
<Image1 width={50} height={50}/>
<Image2 width={50} height={50}/>

Loader output

By default the loader outputs ES2015 code (with JSX compiled to JavaScript using babel-preset-react). You can combine it with babel-loader to compile it down to ES5.

// In your webpack config
{
  test: /\.svg$/,
  loaders: [
    {
      loader: 'babel',
      query: {
        presets: ['es2015']
      }
    },
    {
      loader: 'react-svg',
      query: {
        jsx: true
      }
    }
  ]
}

JSX output

Pass loader query jsx=true.

// In your webpack config
{
  test: /\.svg$/,
  loader: 'react-svg?jsx=1'
}

SVGO options

Webpack 1.x

{
  test: /\.svg$/,
  loader: 'react-svg',
  query: {
    svgo: {
      // svgo options
      plugins: [{removeTitle: false}],
      floatPrecision: 2
    }
  }
}

or if you're using with babel-loader, you can

{
  test: /\.svg$/,
  loader: 'babel!react-svg?' + JSON.stringify({
    svgo: {
      // svgo options
      plugins: [{removeTitle: false}],
      floatPrecision: 2
    }
  }),
}

Webpack 2.x

{
  test: /\.svg$/,
  loaders: [ 'babel',
    {
      loader: 'react-svg',
      query: {
        svgo: {
          plugins: [{removeTitle: false}],
          floatPrecision: 2
        }
      }
    }
  ]
}

Internals

Input SVG

SVG Optimize using SVGO

Babel Transform with preset=react and plugin=svgToComponent

Transformations

Going from bottom up, the following transformations are applied and the same can be checked in the partly annotated source - babel-plugin

1. Hyphenated attributes to camelCase

<svg pointer-events="none">
  <path stroke-width="5"/>
</svg>

is transformed to

<svg pointerEvents="none">
  <path strokeWidth="5"/>
</svg>

2. Style attr string to object

React expects style attribute value to be an object. Also, Hyphenated style names are converted to camel case.

<svg style="text-align: center">
  <circle style="width: 10px"/>
</svg>

is transformed to

<svg style={{textAlign: 'center'}}>
  <circle style={{width: '10px'}}/>
</svg>

3. Propagate props to root element

The props passed to the output component is passed on to the root SVG node and the props already defined are overridden by the props passed.

<svg width="50">
  ...
</svg>

is transformed to

<svg width="50" {...this.props}>
  ...
</svg>

4. class to className

<svg class="hello"/>

is transformed to

<svg className="hello"/>

5. export React.Component

The loader should now export the svg component. And this is done by wrapping it in a Component Class.

<svg>...</svg>

is transformed to

import React from 'react';
export default class SVG extends React.Component {
  render() {
    return <svg>...</svg>;
  }
}

Example

Input SVG
<svg style='text-align: center; width: 100px' pointer-events="stroke">
  <circle cx="50" cy="50" r="25" style="text-align: center;" stroke-width="5" />
</svg>
Output React Component
import React from "react";
export default class SVG extends React.Component {
  render() {
    return <svg
      style={{ textAlign: "center", width: "100px" }}
      pointerEvents={this.props.pointerEvents ? this.props.pointerEvents : "stroke"}
      {...this.props} >
        <circle cx="50" cy="50" r="25" style={{textAlign: "center"}} strokeWidth="5" />
    </svg>;
  }
}

CLI

The react-svg-loader comes with a cli (svg2react) that you can use to convert svg files to react components. Use this tool when you'd want to customize your svg component by hand. Otherwise the loader just works.

`npm bin`/svg2react file1.svg file2.svg

and the following files will be emitted

  • file1.svg.react.js
  • file2.svg.react.js

in the SAME directory as the files

CLI Options

  • --jsx: Outputs JSX code instead of compiling it to JavaScript using babel-preset-react
  • --stdout: Outputs to STDOUT
  • --svgo <config_file>: Supports SVGO Config YAML / JSON / JS
  • --svgo.plugins <...plugins>: Takes in an array of plugins that need to be enabled
  • --svgo.plugins.<plugin> <true|false>: - Enable/Disable the plugin
  • --svgo.floatPrecision $N: Set floatPrecision to N for SVGO. SVGO supports 1-8.
`npm bin`/svg2react file1.svg --es5 -0

Assumptions and Other gotchas

  • Root element is always <svg>
  • SVG is optimized using SVGO

LICENSE

MIT License - https://boopathi.mit-license.org/2015