Skip to content
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 modify next.config.js in next 13.3.0? #860

Open
suenot opened this issue Apr 19, 2023 · 11 comments
Open

How to modify next.config.js in next 13.3.0? #860

suenot opened this issue Apr 19, 2023 · 11 comments

Comments

@suenot
Copy link

suenot commented Apr 19, 2023

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?

@gregberge
Copy link
Owner

If someone has the solution it would be nice to update the documentation.

@arikchakma
Copy link

I'm also facing the kinda same problem for the app dir in Nextjs. But works fine in the pages directory.

@jmagrippis
Copy link

This may be related, about the issuer property:

#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.

@jamesvclements
Copy link

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 /)

@yongsk0066
Copy link

yongsk0066 commented Jun 23, 2023

i solve it like this

    const fileLoaderRule = config.module.rules.find(
      (rule) => rule.test && rule.test instanceof RegExp && rule.test.test(".svg")
    );

@IGassmann
Copy link

IGassmann commented Jun 23, 2023

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;
  },

@ChazUK
Copy link

ChazUK commented Jul 23, 2023

Thanks @IGassmann, would be great if this was listed in the Docs as a change in config for v13

@judewang
Copy link

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.

CleanShot 2023-07-28 at 00 55 31@2x

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;
}

CleanShot 2023-07-28 at 01 07 16

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.

gregberge pushed a commit that referenced this issue Nov 18, 2023
Fixed next.config.js example to a working version per this:
#860 (comment)

Co-authored-by: Jari Mustonen <jari@itsellesi.fi>
@curiosbasant
Copy link

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.

@IGassmann
Copy link

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

@chumaumenze
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests