Open jameswilson opened 2 years ago
Same issue with me
Hi, I am very surprised that it does not work. I think it is a webpack configuration issue more than a SVGR one. By looking at your example I have no idea why it does not work. Maybe someone else could guess.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@jameswilson @julianklumpers
webpack.config.js remove issuer: /\.[jt]sx?$/,
How about for rollup, is there any way to load svg dynamically similar to webpack?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@jameswilson @julianklumpers webpack.config.js remove
issuer: /\.[jt]sx?$/,
If anyone is finding this issue because they used the SVGR NextJS docs to setup webpack, removing the issuer
line fixes the error below:
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type,
currently no loaders are configured to process this file.
FWIW I am using Next 13 with app
router and until I removed that line it failed.
I'm facing a different problem, hopefully someone can help me. I have an UI library with an Icon component:
import clsx from 'clsx';
import styles from './Icon.module.scss';
import { icons } from './icons';
import { Suspense, useMemo } from 'react';
export type IconName = keyof typeof icons;
export type IconProps = React.HTMLAttributes<HTMLDivElement> & {
icon: IconName;
disabled?: boolean;
};
export const Icon: React.FC<IconProps> = ({ icon, disabled = false, ...props }: IconProps) => {
const SvgIcon = useMemo(() => icons[icon], [icon]);
const classNames = clsx(styles.root, disabled ? styles.disabled : '', props.className);
if (!SvgIcon) return null;
return (
<div
{...props}
className={classNames}
>
<Suspense fallback={null}>
<SvgIcon style={{ width: '100%', height: '100%' }} />
</Suspense>
</div>
);
};
export default Icon;
The content of my icons.ts looks like this
import React from 'react';
const lazy = (componentImportFn: Function) =>
React.lazy(async () => {
let obj = await componentImportFn();
return typeof obj.default === 'function' ? obj : obj.default;
});
export const icons = {
Icon1: lazy(async () => import('./assets/ico-icon1.svg')),
Icon2: lazy(async () => import('./assets/ico-icon2.svg')),
Icon3: lazy(async () => import('./assets/ico-icon3.svg')),
Icon4: lazy(async () => import('./assets/ico-icon4.svg')),
}
And my NextJs config looks like this as described here
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
distDir: 'build-next-static',
swcMinify: true,
reactStrictMode: true,
webpack(config) {
// Grab the existing rule that handles SVG imports
const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg'));
config.module.rules.push(
// Reapply the existing rule, but only for svg imports ending in ?url
{
...fileLoaderRule,
test: /\.svg$/i,
resourceQuery: /url/, // *.svg?url
},
// Convert all other *.svg imports to React components
{
test: /\.svg$/i,
// issuer: /\.[jt]sx?$/,
resourceQuery: { not: /url/ }, // exclude if *.svg?url
use: ['@svgr/webpack'],
}
);
// Modify the file loader rule to ignore *.svg, since we have it handled now.
fileLoaderRule.exclude = /\.svg$/i;
return config;
},
};
module.exports = nextConfig;
And when calling the Icon button in a nextjs page e.g.
import { Icon } from 'ui';
export default function Page() {
return (
<>
<Icon icon="Icon1" />
</>
);
}
I'm getting the following error from nextjs
Unhandled Runtime Error Error: Unsupported Server Component type: undefined
Can someone push me in a direction or better have a solution for me ?
I have a similar problem, although with a slightly different error:
So, usage looks something like this (we’re using @svgr/webpack
to transform svg’s on the fly):
const logos = {
brand1: lazy(() => import('path/to/brand1logo.svg')),
brand2: lazy(() => import('path/to/brand2logo.svg')),
};
const LogoComponent = ({ brand }) => {
const Logo = logos[brand];
return (
<Suspense fallback={null}>
<Logo />
</Suspense>
)
}
…and what I’m getting in the console is the following:
react-dom.development.js:17733 Uncaught Error: Element type is invalid. Received a promise that resolves to: /path/to/logo.svg. Lazy element type must resolve to a class or function.
It feels like we’re getting back something that isn’t a valid component, so React does not know what to do with it. In my head, I’d figure that SVGR
would do the transformation from svg
→ react component before the promise resolves (or, at least before React sinks its teeth in it), but perhaps that’s not the case? Any ideas?
Relevant addendum: We’re still on webpack 4.x.x
, which I’m beginning to suspect might be part of the problem…
In another greenfield project where we’re using Next, we’re able to do the above just fine (just using Next’s dynamic()
instead of lazy
/Suspense
). We had to move away from using variables as part of the dynamic import path though (../logos/${brand}.svg
) – never got that to work, regardless of which setup we introduced it to.
💬 Questions and Help
Thank you for this helpful project!
I'm trying to dynamically import SVGs based on a string filename, but I'm a little lost.
Is something like this possible using webpack
import
?When I run the webpack build, I get same error for every SVG in the folder.
webpack.config.js setup following docs:
I've tried adding
'file-loader',
to theuse
to no avail. Apologies if I'm off track in some obvious way, I'm fairly new to SVGR & React. I read somewhere that SVGR creates a mapping during build, so if there is a simpler way to just load the right SVG dynamically based on a string, an example would be great to have in docs. My apologies if this is documented already, I searched, scanned, and couldn't find anything relevant.