parcel-bundler / parcel

The zero configuration build tool for the web. 📦🚀
https://parceljs.org
MIT License
43.38k stars 2.27k forks source link

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

Open ghost opened 2 years ago

ghost commented 2 years ago

🐛 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

hamzamihaidanielx commented 2 years ago

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

jeb5 commented 2 years ago

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

ghost commented 2 years ago

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?

hamzamihaidanielx commented 2 years ago

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

MLNW commented 2 years ago

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

oe commented 2 years ago

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

astegmaier commented 2 years ago

@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:*": ["..."]
  }
}
MLNW commented 1 year ago

@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

jboler commented 1 year ago

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 ; }


To make parcel work with this I had to:
1. Rename inlined SVG files to `*.jsx.svg`
1. Update `.parcelrc`
```json
  "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.
SrBrahma commented 8 months ago

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?

SrBrahma commented 8 months ago

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'),
        },
    ],
},