-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to dynamically introduce it after version 4.0 #90
Comments
I am also getting unexpected behaviour when trying to dynamically import. The import returns a path string instead of a React component. I was playing with a stack blitz from this article that was demoing how to work with vite/svgr and dynamic imports. It references an outdated version of this plugin so I forked the dynamic import stack blitz and updated all the packages. As you can see in this minimal repro the plugin appears to be returning a path string to the component instead of a React component which causes React to blow up. |
I'm also having errors since version 4. My test with vitest returns this error on all my tests that contains a component SVG :
No problem on version 3. |
Same issue here. Dynamic imports do not work as described by @alexbaulch |
It seems caused by the Is this kind of usage working at v3.0? |
@pd4d10 Yes, it's working before Regarding @trungpham71198 's solution, I can't take it since I sometimes still use the normal This critical is preventing me from upgrading to Vite 5, since it's only supported in Please have a look into it, cheers. 💚 |
Just to add my 2 cents it' no solutions seems to work in vitev5 like here https://stackblitz.com/edit/vitejs-vite-fz5lgu?file=src%2FSvgIcon.tsx,package.json |
Still a work-around, but if you still want to import normal svg's you can change the file name of svg's you do want to be picked up by svgr and change the
In vite config: svgr({
include: '**/*.svgr.svg'
}) Then your import should also append await import(`path/to/${iconName}.svgr.svg`) |
Any official fix on this please? @pd4d10 |
This issue is preventing me from upgrading to Vite5 😭 |
Same issue for me, can't dynamically import SVGs after upgrading to version 4 :( |
Any updates? |
@trungpham71198
Thanks for your advice. For me it worked partially. So, I went to
This works for me. |
None of the solutions are working for me. But in any case (unrelated solution, but), as an alternative approach. what's stopping you from just defining: // icons/index.ts
export { default as IconUp } from "./up.svg?react";
export { default as IconDown } from "./down.svg?react";
export { default as IconLeft } from "./left.svg?react";
export { default as IconRight } from "./right.svg?react"; And then just defining a map: import type { ReactNode } from "react";
import { IconUp, IconDown, IconLeft, IconRight } from "./icons";
const dynamicIcons: Record<string, ReactNode> = {
"up": <IconUp />,
"down": <IconDown />,
"left": <IconLeft />,
"right": <IconRight />,
}
// And then using it in your jsx like:
let myDynamicValue = "up" | "down" | "left" | "right";
{dynamicIcons[myDynamicValue]} |
You have defined list of icons. Simple imports works. But dynamic - not :(. |
WAIT! I stand corrected! #90 (comment) - This indeed works lol. Also @VikomiC. The reason why static imports // icon.d.ts (in your root folder)
/**
* So import .svg becomes a ReactComponent instead of a string. Enabled by `vite-plugin-svgr`.
*/
declare module "*.svg" {
import * as React from "react";
const ReactComponent: React.FunctionComponent<
React.ComponentProps<"svg"> & { title?: string }
>;
export default ReactComponent;
} ✅ Anyway, here's the whole code that works:// icon.tsx
type IconSVG =
| "caret-down"
| "chart"
| "copy"; // extend as you wish.
export type IconProps = {
src: IconSVG;
} & React.SVGProps<SVGSVGElement>;
export const Icon = ({ src, ...svgProps }: IconProps) => {
const {loading, SvgIcon } = useDynamicSvgImport(src);
if (loading) {
return null;
}
if (!SvgIcon) return null;
return <SvgIcon width="1em" height="1em" {...svgProps} />
};
/** Reference: https://stackblitz.com/edit/vitejs-vite-fz5lgu?file=src%2FSvgIcon.tsx,package.json */
export function useDynamicSvgImport(iconName: string) {
const importedIconRef = useRef<React.FC<React.SVGProps<SVGElement>>>();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<unknown>();
useEffect(() => {
setLoading(true);
// dynamically import the mentioned svg icon name in props
const importSvgIcon = async (): Promise<void> => {
// please make sure all your svg icons are placed in the same directory
// if we want that part to be configurable then instead of iconName we will send iconPath as prop
try {
importedIconRef.current = (
await import(`@/assets/icons/${iconName}.svg?react`)
).default; // svgr provides ReactComponent for given svg path
} catch (err) {
setError(err);
console.error(err);
} finally {
setLoading(false);
}
};
importSvgIcon();
}, [iconName]);
return { error, loading, SvgIcon: importedIconRef.current };
} // vite.config.ts
export default defineConfig({
...
plugins: [
svgr({
svgrOptions: { icon: true },
include: ['**/*.svg', '**/*.svg?react'],
exclude: [],
}),
],
...
}); |
Maybe a bit different, because I don't want to sue custom hook (as suggested above When I use SIMPLE IMPORT I have all good: const iconModules = import.meta.glob('./*.svg', { eager: true });
export const IconsPage = () => {
return (
<div>
{Object.entries(iconModules).map(([path, module], index) => {
// @ts-ignore
const IconComponent = module.default;
return (
<div key={index} style={{ display: 'inline-block', margin: '10px' }}>
<a href={`src/icons/${path}`}>
<img src={IconComponent} width="30px"></img>
</a>
</div>
);
})}
</div>
);
}; But when I want to rely on const iconModules = import.meta.glob('./*.svg?react', { eager: true }); // CHANGED
export const IconsPage = () => {
return (
<div>
{Object.entries(iconModules).map(([path, module], index) => {
// @ts-ignore
const IconComponent = module.default;
return (
<div key={index} style={{ display: 'inline-block', margin: '10px' }}>
<a href={`src/icons/${path}`}>
<IconComponent width="30px" /> // CHANGED
</a>
</div>
);
})}
</div>
);
}; Problem is that SHOULD I be able to dynamically render SVG icons this way? Have I missing something? PS1. When I include single SVG icon file all is ALSO GOOD: import ErrorIcon from '@icons/error_icon.svg?react';
import DeleteIcon from '@icons/delete.svg?react'; PS2. I also tried importing this way: const iconModules = await import('./*.svg').then(module => module.default); But then Vite Build fails at all. Yes, I assumed import can return me array of modules :) PS3. |
How to dynamically introduce it after version 4.0?
The text was updated successfully, but these errors were encountered: