1

In some places, I need to import my SVG file as a component, to have a control on it ( change style for example, change the fill color of the SVG element ) I used SVGR for that, and in other places, I want to use the SVG file as a normal image and get benefit with the built-in "next/image" module features.

I can't use next/image module as when I import it like

import FacebookIcon from "public/images/icons/social/facebook.svg";

FacebookIcon is a component.

Not a format that the src attribute of next/image component can accept.

From what I understood is src accept string or object with this format

{ src: "**", width: **px, height: **px }
Mina
  • 14,386
  • 3
  • 13
  • 26
  • 1
    Does this answer your question: [Getting NextJS Image Component & @svgr/webpack to play nicely together](https://stackoverflow.com/questions/66764119/getting-nextjs-image-component-svgr-webpack-to-play-nicely-together)? – juliomalves May 17 '22 at 21:58
  • 1
    Yes, that's exactly I reached out recently by reading the SVGR Webpack documentation but there is a missing piece issue with this approach that I must to specify the width and height every time I need to use next/image, by defaut if I didn't use any image loader, next gives an object when import an image with this format { src: '**', height: **px, width: **px } by extracting the actual width an height of the svg file, so I don't need to specify the width and height, ** That's important to me because I use next/image everywhere an the application and without that I need to modify a lot of code. – Mina May 18 '22 at 06:14
  • So, I wonder what is the next default webpack loader to use it next to '@svgr/webpack' instead of using 'url-loader' to give me this format { src: "**", width: **px, height: **px } – Mina May 18 '22 at 06:21

1 Answers1

1

Desired usage

import MySVG from "./mySVG.svg?svgr"; // SVGR loader

<MySVG />

import Image from "next/image";
import mySVG from "./mySVG.svg"; // Default NextJS loader

<Image src={mySVG} alt="" /> // (width and height will be applied automatically)

Required next.config.js

webpack(config, { dev: isDev, isServer }) {

    config.module.rules.push({
      test: /\.svg$/i,
      issuer: /\.[jt]sx?$/,
      resourceQuery: /svgr/, // only use svgr to load svg if path ends with *.svg?svgr
      use: ["@svgr/webpack"],
    });

    // Re-add default nextjs loader for svg
    config.module.rules.push({
      test: /\.svg$/i,
      loader: "next-image-loader",
      issuer: { not: /\.(css|scss|sass)$/ },
      dependency: { not: ["url"] },
      resourceQuery: { not: [/svgr/] }, // Ignore this rule if the path ends with *.svg?svgr
      options: { isServer, isDev, basePath: "", assetPrefix: "" },
    });

}

Required typescript declaration (if using ts)

declare module "*.svg?svgr";

How I figured it out

  1. Read these docs: https://react-svgr.com/docs/webpack/
  2. Used this snippet to get the default rule applying to svgs
webpack(config) {
    const defaultSvgLoader = config.module.rules.find(
      (rule) => typeof rule?.test?.test === "function" && rule.test.test(".svg")
    );
    console.log(defaultSvgLoader);
}
  1. Added resourceQuery: { not: [/svgr/] } into the logged output object so that *.svg?svgr paths will be ignored
Loki
  • 53
  • 5