Does CRA App Include SVGs in the Bundle By Default?

Shweta Singh
The Startup

--

The 16.x version of react brought with it the capability of creating a bundle of the application files and serving it in multiple chunks. The lazy-loading became easier. It gave us the privilege of code splitting and avoid fetching unnecessary modules and files from the server.

With all the things said above, the chunk size can be reduced, which can result in performance improvement. Even though we can achieve a significant improvement in performance by using the code splitting feature intelligently.
✅ JS files can be served into chunks.
✅CSS files can be served into chunks.

What about the images?

Does the default webpack configuration for a react application created with CRA include svg files too in chunking?

I realized even though I had used the import statement for getting the SVG images, there were still one browser request per image. Sending extra requests to fetch SVG images is definitely not a great idea. Specially, if there are number of images on the page.

To reduce the calls, i tried using SVG sprites. That works, but still there should be a way to bundle the svg images with JS right? After digging somewhat, I came across SVGR library which could help us to use the SVG Images as React Component.

import React from 'react'const SvgComponent = props => (<svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 257.002 297.5" {...props} >
<g transform="matrix(0.8526811,0,0,0.8526811,18.930632,21.913299)">
<polygon points="8.003,218.496 0,222.998 0,74.497 8.003,78.999 8.003,218.496 "/>
<polygon points="128.501,287.998 128.501,297.5 0,222.998 8.003,218.496 128.501,287.998 "/>
<polygon points="249.004,218.496 257.002,222.998 128.501,297.5 128.501,287.998 249.004,218.496 "/>
<polygon points="249.004,78.999 257.002,74.497 257.002,222.998 249.004,218.496 249.004,78.999 "/>
<polygon points="128.501,9.497 128.501,0 257.002,74.497 249.004,78.999 128.501,9.497 "/>
<polygon points="8.003,78.999 0,74.497 128.501,0 128.501,9.497 8.003,78.999 "/>
</g>
</svg>
)
export default SvgComponent

This way, when we import and use it as a component, it can be controlled and maintained easily along with bundling.

But wouldn’t it be nice if we would have got this feature by default in our application scaffolded by CRA? And please no ejection!!! 🙏

🎉 🎉We have SVGR already configured with Webpack 4 as a plugin.. 🎉

Let’s see how?

/** added in webpack.config.js by default by CRA */svg: {ReactComponent:'@svgr/webpack?-svgo,+titleProp,+ref![path]',}

☑️ good news !! No ejection of webpack config needed.

Let’s see how it works ❓

/** code excerpt from one of the react scripts */
import * as React from 'react';
export const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement> & { title?: string }>;const src: string;export default src;

Whenever a SVG file is encountered, it is converted as the above functional component by the SVGR.

As we can see, it exports the src string by default.

Hence in import MyIcon from “../icon.svg”, MyIcon has only the source path. And that’s the reason, it doesn’t get included in the bundle since we are just replacing the string and not the image.

What is the other ReactComponent exported?

ReactComponent is the functionalComponent which exposes the SVG Icon as a component and makes it easier to work with. And above all, since its a component, it can be taken into consideration for creating the chunks which can result in components smaller than the image itself. YAYYY!! So no SVG Sprites needed, and our problem is also solved.

How to use it?

import {ReactComponent as MyIcon} from "../assets/images/icon.svg";
import {ReactComponent as MyIcon} from "../assets/images/icon2.svg";
....
<MyIcon className="my-class" title="Any text which will be shown on hover" />
....

Difference between using the src and this as a ReactComponent.

If we use src in an img tag, the svg will be fetched from the source URL, while the ReactComponent renders the SVG image inline.

The Advantages?

✔️ Size reduction: The conversion to ReactComponent is smaller than the SVg itself.

✔️ Since its a component, therefore, easy to use and handle and rendered inline therefore we can control it easily.

✔️ SVG images bundled with JS, therefore no extra fetch browser calls, not even SVG Sprites needed.

✔️ Converting SVG to a component can be helpful in customizing the images.

With enough said, the bottom line is we do not need to take extra care of the SVGs anymore. CRA has already provided a way to do it. And if not CRA, simple webpack configuration should be able to handle it.

--

--