'Getting NextJS Image Component & @svgr/webpack to play nicely together
I have a Next.js site with the @svgr/webpack library installed. I have configured next.config.js to work with @svgr/webpack and now want to import an svg image and use it with the new next/image component.
Here is how I set up my next.config.js file:
module.exports = {
images: {
domains: ["images.vexels.com"],
},
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ["@svgr/webpack"],
});
return config;
},
};
And here is what I am trying to do:
import Image from 'next/image'
import Logo from '@/svg/logo.svg'
<Image src={Logo} width={174} height={84} />
However, when I do that I get the following error:
Unhandled Runtime Error
TypeError: src.startsWith is not a function
Source
client\image.tsx (278:13) @ Image
276 | let isLazy =
277 | !priority && (loading === 'lazy' || typeof loading === 'undefined')
> 278 | if (src && src.startsWith('data:')) {
| ^
279 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
280 | unoptimized = true
281 | isLazy = false
I thought that perhaps I should include the Logo component as an actual component, like this: <Image src={<Logo />} width={174} height={84} />
However, that also did not work.
Any idea what is wrong and how to fix it?
Solution 1:[1]
With your current webpack config importing @/svg/logo.svg will only import the SVG file as a React component.
To import it as a data URL, you will need the following webpack config in your next.config.js.
module.exports = {
images: {
domains: ['images.vexels.com']
},
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader']
});
return config;
}
};
You'll then be able to use it in both ways: as a URL or as a component.
import Image from 'next/image'
import svgUrl, { ReactComponent as Logo } from '@/svg/logo.svg'
<Image src={svgUrl} width={174} height={84} />
// or as a component
<Logo />
Solution 2:[2]
A workaround for this maybe by having a specific pattern for svg file name, and then configuring the default loader to ignore this pattern and svgr/webpack to load matches for this pattern
webpack(config) {
const fileLoaderRule = config.module.rules.find(
(rule) => rule.test && rule.test.test(".svg")
);
fileLoaderRule.exclude = /\.icon\.svg$/;
config.module.rules.push({
test: /\.icon\.svg$/,
loader: require.resolve("@svgr/webpack"),
});
return config;
},
here i'm using the pattern *.icon.svg, so any svg image that ends with it can be used like this
import Logo from "whatever/logo.icon.svg
const Whatever = () => <Logo />
and for other icons this'll work
import Image from "next/image";
import Logo from "whatever/logo.svg"
const Whatever = () => <Image src={Logo} alt="logo" width={100} height={100}/>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | sudofix |
