parcel icon indicating copy to clipboard operation
parcel copied to clipboard

Importing SVG as react component does not work as mentioned in the docs.

Open ghost opened this issue 3 years ago • 11 comments

🐛 bug report

I am trying to import SVG as react component based on the documentation from parcel site. Instead of the svg being rendered as a component in the page, the build actually fails. With an error - @parcel/core: No transformers found for src/assets/logo.jsx with pipeline: 'jsx'.

🎛 Configuration (.babelrc, package.json, cli command)

Using default babel configuration.

// package.json

{
  "name": "parcel-react-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "parcel src/index.html"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@parcel/transformer-svg-react": "^2.2.1",
    "parcel": "^2.2.1"
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  }
}
// .parcelrc

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

🤔 Expected Behavior

The svg image should be loaded as a react component in the webpage.

😯 Current Behavior

An error is thrown saying @parcel/core: No transformers found for src/assets/logo.jsx with pipeline: 'jsx'.

💁 Possible Solution

🔦 Context

I am trying to import a svg image as a react component.

💻 Code Sample

Clone this repo and run yarn && yarn run dev

🌍 Your Environment

Software Version(s)
Parcel 2.2.0
Node 16.13.2
npm/Yarn 8.1.2 / 1.22.17
Operating System Windows 10

Attachments:

error shown in browser

ghost avatar Jan 21 '22 18:01 ghost

Im getting the very same, this is for quite a while. No one has got a workaround or a fix for it yet right?

hamzamihaidanielx avatar Jan 26 '22 08:01 hamzamihaidanielx

One possible workaround is to add "jsx:*": ["..."] below your existing svg transformer.

jeb5 avatar Feb 01 '22 03:02 jeb5

One possible workaround is to add "jsx:*": ["..."] below your existing svg transformer.

This actually makes it work. Should i consider this issue to be resolved?

ghost avatar Feb 01 '22 17:02 ghost

No, its not resolved, this is a workaround not a fix.

hamzamihaidanielx avatar Feb 01 '22 17:02 hamzamihaidanielx

One possible workaround is to add "jsx:*": ["..."] below your existing svg transformer.

When we apply this workaround the error is gone but parcel gets stuck Optimizing index.html...

Our .parcelrc:

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

By removing the last line, starting with *.{js,mjs,jsx,cjs}" it suddenly works, though I am unsure if we still require this pipeline.

EDIT: Sadly there are still issues which I am unable to diagnose as the Website simply does not render. The only error I get is this:

grafik

MLNW avatar Feb 24 '22 09:02 MLNW

same issue with "@parcel/transformer-svg-react": "^2.5.0"

oe avatar Apr 22 '22 08:04 oe

@MLNW - I hit the same error that you did - I think it's related to #7389

I found two workarounds: (1) remove inline style props on any svgs you are importing through your jsx:*.svg named pipeline or (2) remove the @transformer/svg plugin from that pipeline (i.e. remove the "..." entry, which includes this by default). The final config that worked for me was:

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

astegmaier avatar May 04 '22 18:05 astegmaier

@astegmaier I somehow missed your comment. It looks promising. Sadly I have moved on from the project for now so I can't test your solution at the moment

MLNW avatar Nov 01 '22 06:11 MLNW

My project uses SVG files in 2 ways:

  1. Inline React components
import Icon from "./icon.svg";

function Component() {
  return <Icon />;
}

  1. As img src
import icon from "./icon.svg";

function Component() {
  return <img src={icon} />;
}

To make parcel work with this I had to:

  1. Rename inlined SVG files to *.jsx.svg
  2. Update .parcelrc
  "transformers": {
    "*.jsx.svg": ["@parcel/transformer-svg-react"],
    "*.{js,mjs,jsx,cjs,ts,tsx}": [
      "@parcel/transformer-js",
      "@parcel/transformer-react-refresh-wrap"
    ]
  }
  1. Add a type definition:
declare module '*.jsx.svg' {
  import { FunctionComponent, SVGProps } from 'react';

  const svg: FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;
  export default svg;
}

declare module '*.svg' {
  const src: string;
  export default src;
}

It's not ideal because I cannot use the same image file both inline and as image but it works.

jboler avatar Mar 01 '23 18:03 jboler

While https://github.com/parcel-bundler/parcel/issues/7587#issuecomment-1117652812 works, this named pipeline conflicts with Storybook's webpack. Anyway to have it working without the named pipeline?

ftzi avatar Jan 04 '24 14:01 ftzi

I kept the named pipeline and created this webpack plugin so storybook can remove the jsx: from the import:

module.exports = function (source) {
    return source.replace(/import\('jsx:(.*\.svg)'\)/g, "import('$1')")
}

And have it in the storybook's webpack rules' array:

{
    test: /\.(ts|tsx)$/,
    use: [
        {
            loader: path.resolve(__dirname, 'renameJsxImport.js'),
        },
    ],
},

ftzi avatar Jan 04 '24 15:01 ftzi