svgr
svgr copied to clipboard
How to modify next.config.js in next 13.3.0?
After install nextjs I have next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
module.exports = nextConfig
In svgo docs another format of next.config.js:
module.exports = {
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
},
// ...other config
}
As I understand, I need rewrite config in docs in new format. Could you help with that?
If someone has the solution it would be nice to update the documentation.
I'm also facing the kinda same problem for the app
dir in Nextjs. But works fine in the pages directory.
This may be related, about the issuer
property:
https://github.com/gregberge/svgr/issues/726
But for me I managed to make it work with a different issuer (the same fileLoaderRule
uses), and using the loader
and options
keys, instead of use: ['@svgr/webpack']
.
So, what I have is:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
typedRoutes: 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: {not: /\.(css|scss|sass)$/},
resourceQuery: {not: /url/}, // exclude if *.svg?url
loader: '@svgr/webpack',
options: {
dimensions: false,
titleProp: true,
},
}
)
// Modify the file loader rule to ignore *.svg, since we have it handled now.
fileLoaderRule.exclude = /\.svg$/i
return config
},
}
module.exports = nextConfig
Pass your own options to taste, but note loader: '@svgr/webpack'
: '@svgr/webpack'
is a string, not an array as it is in the docs, with use
.
Using @jmagrippis's issuer: issuer: {not: /\.(css|scss|sass)$/},
worked for me in next ^13.3.2-canary.12
Before that, I was getting this compilation error:
Module parse failed: Unexpected token (1:0) You may need an appropriate loader to handle this fi...
Oddly this error only showed up on a sub-page (/about
instead of /
)
i solve it like this
const fileLoaderRule = config.module.rules.find(
(rule) => rule.test && rule.test instanceof RegExp && rule.test.test(".svg")
);
Here's how I solved it:
webpack(config) {
// Configures webpack to handle SVG files with SVGR. SVGR optimizes and transforms SVG files
// into React components. See https://react-svgr.com/docs/next/
// Grab the existing rule that handles SVG imports
// @ts-ignore - this is a private property that is not typed
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: fileLoaderRule.issuer,
resourceQuery: { not: [...fileLoaderRule.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;
},
Thanks @IGassmann, would be great if this was listed in the Docs as a change in config for v13
Since Next has image-type built in and it sets *.svg
type as any
, I found that I kept customizing the webpack config and type reference to just let the loader work with the svg file path without query and have a type safe environment.
Then I just think, what about doing this reversely?
const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg'));
I found that what we do in this line is finding the next-image-loader
rule, I tried letting it does its job and add another feature to load svg by svgr loader. Here's my config:
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: withSVGR,
};
export default nextConfig;
function withSVGR(config) {
const nextImageLoaderRule = config.module.rules.find((rule) =>
rule.test?.test?.(".svg"),
);
nextImageLoaderRule.resourceQuery = {
not: [...nextImageLoaderRule.resourceQuery.not, /icon/],
};
config.module.rules.push({
issuer: nextImageLoaderRule.issuer,
resourceQuery: /icon/, // *.svg?icon
use: ["@svgr/webpack"],
});
return config;
}
// global.d.ts
interface SVGIcon
extends React.FunctionComponent<React.SVGAttributes<HTMLOrSVGElement>> {}
declare module "*.svg?icon" {
const content: SVGIcon;
export default content;
}
It's ok for me to just add the ?icon
query for importing the svg icon through svgr-loader, and I can type the imported module easily without other hack. I think this way may reduce conflicts with next.js built-in settings.
Here's how I solved it:
webpack(config) { // Configures webpack to handle SVG files with SVGR. SVGR optimizes and transforms SVG files // into React components. See https://react-svgr.com/docs/next/ // Grab the existing rule that handles SVG imports // @ts-ignore - this is a private property that is not typed 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: fileLoaderRule.issuer, resourceQuery: { not: [...fileLoaderRule.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; },
How can I add options in here?
Like I want to keep the viewBox
attribute.
Here's how I solved it:
webpack(config) { // Configures webpack to handle SVG files with SVGR. SVGR optimizes and transforms SVG files // into React components. See https://react-svgr.com/docs/next/ // Grab the existing rule that handles SVG imports // @ts-ignore - this is a private property that is not typed 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: fileLoaderRule.issuer, resourceQuery: { not: [...fileLoaderRule.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; },
How can I add options in here? Like I want to keep the
viewBox
attribute.
You can pass custom options by replacing use: ['@svgr/webpack'],
with use: [{ loader: '@svgr/webpack', options: { icon: true } }],
. Alternatively, you can use a SVGR configuration file and/or a SVGO configuration file.
Here's an example of a configuration that configs SVGO to not remove the viewBox
attribute: https://github.com/IGassmann/web-app-template/blob/6f766e921220145d858dce2fc4c448f162b18d4c/svgo.config.js#L16
Error still in Next.js 14.2.4
⨯ ./src/assets/logo.svg
TypeError: Cannot read properties of undefined (reading '0')
at Array.filter (<anonymous>)
Import trace for requested module:
./src/assets/logo.svg