Search code examples
reactjssvgparceljs

How do you use an SVG inline in React using Parcel 2?


Previously in Parcel v1 you could just use something like the @svgr/parcel-plugin-svgr plugin for Parcel. This would give you the ability to use SVGs inline like when using CRA:

import Star from './star.svg'

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

Can anyone help figure out a way to do this in Parcel 2?


Solution

  • Parcel2 provides the @parcel/transformer-svg-react plugin to accomplish this.

    Here's what you need to do:

    1. Install it:

      yarn add @parcel/transformer-svg-react --dev
      
    2. Add a .parcelrc file at the root of your project that defines a named pipleine that uses this plugin:

      {
        "extends": "@parcel/config-default",
        "transformers": {
          "jsx:*.svg": ["...", "@parcel/transformer-svg-react"]
          "jsx:*": ["..."]
        }
      }
      

      (The "..." entry should actually be typed into the .parcelrc file - it tells parcel "process these kinds of assets as usual, and only after you are done, transform it into a react component.")

      Update (5/2022) I added the "jsx:*": ["..."] line, which appears to currently be a necessary workaround to avoid this bug.

      Another current "gotcha" is that if the SVG files that you want to transform into react components contain inline style tags (e.g. <path style="fill:red" ...>, you'll run into this bug. To avoid it, you'll want to remove the @parcel/transformer-svg plugin from your pipeline by modifiying the first transformer line to read "jsx:*.svg": ["@parcel/transformer-svg-react"] (i.e. remove the ...).

    3. Use the named pipeline in your import statements:

      import Star from 'jsx:./star.svg'
      
      const App = () => (
        <div>
          <Star />
        </div>
      )
      
    4. (optional, if you use TypeScript). Let TypeScript know about the jsx: named pipeline by using a wildcard module declaration. In a d.ts file that's a part of your typescript project, write this:

      declare module "jsx:*.svg" {
        import { ComponentType, SVGProps } from "react";
        const SVGComponent: ComponentType<SVGProps<SVGSVGElement>>;
        export default SVGComponent;
      }
      

    See parcel 2 documentation.