pd4d10 / vite-plugin-svgr

Vite plugin to transform SVGs into React components
MIT License
554 stars 54 forks source link

vite, react-ts --- Module '"*.svg"' has no exported member 'ReactComponent'. --- #44

Open ElBambu opened 2 years ago

ElBambu commented 2 years ago

Hello i just installed this module in a vite/react-ts project, i'm getting this error when i'm importing an SVG

import { ReactComponent as HomeIcon } from "images/icons/IconSvg/home.svg"

The import works and the icon is shown.

I managed to get rid of the error by declaring this module

declare module "*.svg" {
  import * as React from "react";

  export const ReactComponent: React.FunctionComponent<
    React.SVGProps<SVGSVGElement> & { title?: string }
  >;

  const src: string;
  export default src;
}

It doesn't really bother me, but i was wondering if there is a " cleaner " solution

Thanks for your responses :)

pd4d10 commented 2 years ago

If I understand it correctly, there is a section in the readme you can refer to:

If you are using TypeScript, there is also a declaration helper for better type inference:

/// <reference types="vite-plugin-svgr/client" />

and you don't need to declare it manually

Wiz1991 commented 2 years ago

You can add this to your tsconfig.json under compiler options and it will pick up the types

    "types": ["vite-plugin-svgr/client"]

If you are on VSCODE and it doesnt pick it up straight away, either restart vscode or ts server

aslanalyiev commented 1 year ago

pd4d10

Added inside client.d.ts: /// <reference types="vite-plugin-svgr/client" />

But got this error:

image
sedatbasar commented 1 year ago

Put this to your vite-env.d.ts

/// <reference types="vite-plugin-svgr/client" />

DigitalNaut commented 1 year ago

I'm having a similar issue, except I can compile but I'm getting this in my browser console log:

Version: 2.4.0

Uncaught SyntaxError: ambiguous indirect export: ReactComponent

I have:

//vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";

export default defineConfig({
  plugins: [react(), svgr()],
  resolve: {
    alias: {
      src: "/src",
    },
  },
});
//vite-env.d.ts
/// <reference types="vite/client" />
/// <reference types="vite-plugin-svgr/client" />
// Component
import { ReactComponent as Icon} from '/src/assets/icon.svg';

I've also tried:

//vite-env.d.ts
"types": [
  "vite/client",
  "vite-plugin-svgr/client"
],
panjiangyi commented 1 year ago

Hey guys, I figured it out.

I bet all you guys struggled of this issue had setexportAsDefault to true.

The type definition of this library is export a variable called "ReactComponent" when you import a svg file, not default export.

declare module '*.svg' {
  import * as React from 'react'

export const ReactComponent: React.FunctionComponent<
    React.ComponentProps<'svg'> & { title?: string }
  >
}

so Don't set the exportAsDefault to true, which will export svg component as default export, which result in confilit with svg declaration from vite.

use this plugin like this:

import { ReactComponent as SvgIcon } from './xxx.svg';
lucsky commented 1 year ago

@panjiangyi So what's the point of exportAsDefault then?

h2thien commented 1 year ago

@lucsky IMO it gives you a choice, or compromise. If you think having to type .svg imports yourself is worth the effort to not need to rename the import every time, then exportAsDefault: true is for you.

h2thien commented 1 year ago

That being said, as an OSS, I think the best course of action here is for a community hero to provide the typing for when exportAsDefault: true. That is, when that option is enabled, you should only need to do:

/// <reference types="vite-plugin-svgr/client-default" />
MHebes commented 1 year ago

Does anyone have a way to get the vite-plugin-svgr/client types to take precedence over the vite/client types? My vite-env.d.ts looks like this:

/// <reference types="vite/client" />
/// <reference types="vite-plugin-svgr/client" />

And my svg imports are still typed as string instead of { ReactComponent }. Swapping the lines around doesn't work. Deleting the vite/client line does work, but then breaks my other modules' types.

spoilerdo commented 1 year ago

Add the following to your tsconfig:

{
  "compilerOptions": {
    "types": ["vite/client", "vitest/globals", "vite-plugin-svgr/client"],
    }
  }
}
SleighJ commented 1 year ago

Have tried all suggested answers here and in documentation to no avail..

truxiein commented 1 year ago

Tried everything from here and from stackoverflow. Nothing works. I always end up with Uncaught SyntaxError: ambiguous indirect export: ReactComponent.

Also tried doing what OP did, but no luck. Also added reference types, but no luck.

currently vite.config.ts has this plugins: [react(), svgr({svgrOptions: {exportType: "named", ref: true}})], also played around with svgrOptions, but no luck.

I am really clueless after one day to trial and error.

pd4d10 commented 1 year ago

ReactComponent named export is for v3 and prior versions.

For the latest v4, please check out the document here: https://github.com/pd4d10/vite-plugin-svgr?tab=readme-ov-file#usage

Background here: https://github.com/pd4d10/vite-plugin-svgr/pull/71#issuecomment-1727006445

MrRobz commented 11 months ago

If using v4 of this package, you need to change your imports from

import { ReactComponent as Icon} from '/src/assets/icon.svg';

to

import Icon from '/src/assets/icon.svg?react';
xxKeefer commented 11 months ago

i hope this helps someone, i resolved this issue by moving vite-env.d.ts inside of my ./src directory

chawax commented 10 months ago

If using v4 of this package, you need to change your imports from

import { ReactComponent as Icon} from '/src/assets/icon.svg';

to

import Icon from '/src/assets/icon.svg?react';

It looks like this syntax is not supported with Jest :(

sagarpanchal commented 9 months ago

@chawax vitest-dev/vitest

lukomwro commented 9 months ago

Tried everything from here and from stackoverflow. Nothing works. I always end up with Uncaught SyntaxError: ambiguous indirect export: ReactComponent.

Also tried doing what OP did, but no luck. Also added reference types, but no luck.

currently vite.config.ts has this plugins: [react(), svgr({svgrOptions: {exportType: "named", ref: true}})], also played around with svgrOptions, but no luck.

I am really clueless after one day to trial and error.

You need to add include: '**/*.svg' prop to svgr plugin configuration. Vite config should looks like this:

plugins: [
    react(),
    svgr({
      svgrOptions: { exportType: 'named', ref: true },
      include: '**/*.svg',
    }),
],
garryxiao commented 3 months ago

I would like to suggest improve the "vite-plugin-svgr/client" with another case when import the SVG icon with URL (like from the public folder of React application):

const ReactComponent: React.FunctionComponent< React.ComponentProps<"svg"> & { title?: string }

;

declare module "*.svg?react" { export default ReactComponent; }

declare module "*.svg?url&react" { export default ReactComponent; }

MrModest commented 2 months ago

@MrRobz

If using v4 of this package, you need to change your imports from

With this approach, TS won't allow you to use SVG properties like fill. It will complain:

Type '{ fill: string; }' is not assignable to type 'IntrinsicAttributes'.
  Property 'fill' does not exist on type 'IntrinsicAttributes'.
KingMatrix1989 commented 2 months ago

hey guys, the plugins don't have a named export. Look at the following code:

declare module "*.svg?react" {
  import * as React from "react";

  const ReactComponent: React.FunctionComponent<
    React.ComponentProps<"svg"> & { title?: string }
  >;

  export default ReactComponent;
}

In addition, it just defines a ReactComponent type for imports like *.svg?react so:

  1. Plugin Recommended Way: Import SVG file as ReactComponent using import SvgIcon from 'icon.svg?react

  2. Custom Solution: Change plugin config to exportType: 'named' then override the plugin and vite types for SVG files. For this purpose, you can create a declaration file like custom.d.ts and include it using tsconfig.json (before src).

//custom.d.ts
declare module "*.svg" {
  import * as React from "react";

  const ReactComponent: React.FunctionComponent<
    React.ComponentProps<"svg"> & { title?: string }
  >;

  export { ReactComponent };
}

Be flexible to changes :)

MrModest commented 2 months ago

Thank you @KingMatrix1989 !

  1. Declared SVG module as you suggested in "Custom Solution"
  2. Changed plugin config to exportType: 'named'
  3. imported as import { ReactComponent as GenericPoiIcon } from '@/assets/GenericPoiIcon.svg'
  4. And now I can call SVG attributes like <GenericPoiIcon fill='gray' /> with no complaints from Typescript