How To Integrate SVG For Website And React App With Webpack
Tags: webpack, javascript, react, webdev
Published: 2021-09-08 08:00:15

In this post, we will see how to use SVG images in a website and React app. We'll learn how to integrate, simplify, optimize and automate the use of SVG with Webpack.

## What is SVG

Scalable Vector Graphics is an XML-based vector image format. It's an open format supported by the W3C. All modern browsers (Firefox, Chrome, Opera, Safari, Edge) have SVG rendering support. W3C create this format for websites a few years ago. Let's take a look at some advantages of SVG:

* Scalability and resolution: this is the main advantage. It doesn't use pixels but vector computation, so the image is scalable and is adapted to all screen resolutions.
* High performance: the SVG format is light and, the browser can render it fast.
* DOM styling: the SVG can be inline to the HTML. So, CSS can style it, and javascript can manipulate it as a DOM element.

## HTML5 and the SVG format

### State of the support of SVG format

SVG stable version is the SVG 1.1-second edition. Almost all browsers have great support for SVG rendering. Note, the specification is not trivial, and browsers don't implement all specs. For more details about SVG 1.1 browser support, see [caniuse.com](https://caniuse.com/svg).

![Antoine AMARA SVG Webpak Integration Blog Post SVG Website Support](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6amcl9xibu2av1ktur48.png)

After this introduction, let's see how to load SVG.

### How to load SVG as an image

The IMG tag can load the SVG as an image. With an IMG tag, the image is not vectorial anymore, and the advantage of scalability is lost.

`index.html`

```html
<body>
  <img src="img/example.svg" />
</body>
```

### How to inline SVG

Another way to display an SVG is to inline the XML directly into the HTML file. It's the better way to use SVG because the browser will compute the vectors and keep all advantages of it.

`index.html`

```html
  <body>
    <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 100px 100px">
      <circle r="50px" cx="50px" cy="50px" fill="#08415c" />
    </svg>
  </body>
```

We have seen how to manually add SVG images into a static website. The aim is now to automate this operation with Webpack.

## Website integration through Webpack

Almost every website and web app use Webpack as a bundler to apply some operations on the assets. An easy way to make the SVG integration is to use a Webpack plugin to automatically inline the SVG files' content to the bundled HTML.

Let's use `html-webpack-plugin` to manage the HTML files as a template with Webpack. We can use `html-webpack-inline-svg-plugin` in addition to this one to manage SVG into our HTML template. This plugin can easily inline some SVG's to HTML files by simply using an IMG tag with an "inline" attribute.

Let's install these plugins:

`shell`

```shell
# NPM
npm install --save-dev html-webpack-plugin html-webpack-inline-svg-plugin
# Or Yarn
yarn add -D html-webpack-plugin html-webpack-inline-svg-plugin
```

Now, add some configurations to manage HTML and SVG, add it to webpack.js (or webpack.comon.js if you split the configurations into multiple files).

`webpack.common.js`

```js
...otherImports
import HtmlWebpackPlugin from "html-webpack-plugin";
import HtmlWebpackInlineSVGPlugin from "html-webpack-inline-svg-plugin";

module.exports = {
  ...otherWebpackConfigs,
  plugins: {
    ...otherPluginsConfigs,
    new HtmlWebpackPlugin({
      filename: "index.html",
      template: "src/index.html",
      chunks: ["main"]
    }),
    new HtmlWebpackInlineSVGPlugin({
      runPreEmit: true,
    }),
  },
};
```

To inline an SVG, you have to use the IMG HTML tag and add an inline attribute. Webpack will replace the tag and inline the XML from the file.

`index.html`

```html
<body>
  <img inline src="src/img/logo.svg">
</body>
```

> **Note**: the image path is a relative path from the project root. It's because I add `src/img/` and not `img/`.

We know how to integrate SVG into a static website. Now, let's see what to do if we use React to construct the frontend.

## React app integration

### How to integrate SVG with create-react-app

`create-react-app` is the easiest way to init a React application. It comes with some Webpack configurations.
The first way to load an SVG is to import the file to your component and load it as an image.

`App.js`

```js
import logo from "./img/logo.svg";

const App = () => {
  return <div>
    <img src={logo} alt="Logo" />
  </div>
}
```

Or to directly inline the XML into the JSX:

`App.js`

```js
const App = () => {
  return <div>
    <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 100px 100px">
      <circle r="50px" cx="50px" cy="50px" fill="#08415c" />
    </svg>
  </div>
}
```

But, `react-script` (the component used by `create-react-app`) can use the Svgr plugin to convert the imported SVG as a component. The created React component will inline the XML from the SVG file inside the DOM.

`App.js`

```js
import { ReactComponent as Circle } from "./img/circle.svg";

const App = () => {
  return <div>
    <Circle />
  </div>
}
```

Now, we can use SVG with create-react-app, but it is interesting to know more about the configuration of Webpack to convert an SVG image to React component.
Let's see how to integrate SVG with a custom Webpack configuration for React application.

### How to integrate SVG with a custom webpack configuration

We have seen `react-scripts` use the Svgr plugin to create React component for inlining SGVs in the DOM.
Let's deep dive into the Svgr configuration with Webpack:

First, install the Svgr webpack plugin:

`shell`

```shell
# npm
npm install --dev @svgr/webpack
# or with yarn
yarn add -D @svgr/webpack
```

Next, let's configure Webpack:

`webpack.common.js`

```js
module.exports = {
  ...otherWebpackConfigs,
  module: {
    rules: [
      ...otherAssetsRules,
      // intercept images format
      {
        test: /\.(png|jp(e*)g)$/,
        use: [{
          loader: "url-loader",
          options: { ...loaderOptions  }
        }]
      },
      // intercept svg and use svgr to convert them to React Components
      {
        test: /\.svg/',
        use: ["@svgr/webpack"],
      },
    ],
  },
};
```

Finally, let's import and easily inline an SVG into a component:

`App.js`

```js
import Circle from "./img/circle.svg";

const App = () => {
    return <div>
      <Circle />
    </div>
}
```

Now, we can use SVG in a website and React app. The last step is to optimize SVG to load it quickly.

## How to optimize SVG contents

SVG files can contain redundant and useless information, especially when they are created with an editor. We can safely remove the useless information from the XML. SVGO (SVG Optimizer) is here to automate these operations.

> **Note**: the html-inline-svg-plugin already uses SVGO to optimize SVG before inlining them into the HTML.

Install SVGO cli:

`shell`

```shell
# NPM
npm install -g svgo
# Or Yarn
yarn global add svgo
```

To optimize one SVG:

`shell`

```shell
svgo img/test.svg
```

To optimize all SVG files within a directory:

`shell`

```shell
svgo -f ./img
```

### Automate SVG optimization with webpack

Webpack can use SVGO with svgo-loader:

Install the loader:

`shell`

```shell
# NPM
npm install -D svgo-loader
# Or Yarn
yarn add -D svgo-loader
```

Add the loader to Webpack configurations:

`webpack.comon.js`

```js
module.exports = {
  ...otherWebpackConfigs,
  module: {
    rules: [
      ...otherAssetsRules
      {
        test: /\.svg/,
        use: [...otherLoadersForSVG, 'svgo-loader'],
      },
    ],
  },
}
```

## Conclusion

W3C creates SVG for the web and, it is good to display a logo, to use some icons or illustrations for a website or a web application. Webpack can easily handle SVG optimization and inlining for complete integration to web apps.

Finally, this article presents the integration for Webpack but, some alternative exists for other bundlers (parcel, ...) and other UI frameworks (VueJS, AngularJS, ...).