@svgr/webpack ์ ์šฉ๊ธฐ (feat. storybook ์—๋Ÿฌ)

2025. 10. 26. 21:57ใ†Trouble Shooting & Issues/Linkiving

๋ฐ˜์‘ํ˜•

๋ชฉ์ฐจ

1. ์•„์ด์ฝ˜ ์ปดํฌ๋„ŒํŠธ, next/image๋ฅผ ์•ˆ์“ด๋‹ค๊ณ ?

2. @svgr/webpack

3. ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ ๊ณผ์ •

4. storybook ์—๋Ÿฌ

5. ๊ฒฐ๊ณผ๋ฌผ


1. ์•„์ด์ฝ˜ ์ปดํฌ๋„ŒํŠธ, next/image๋ฅผ ์•ˆ์“ด๋‹ค๊ณ ?

ํ”„๋กœ์ ํŠธ์—๋Š” IconButton ์ปดํฌ๋„ŒํŠธ์— ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ž„์‹œ ์ปดํฌ๋„ŒํŠธ์ธ, CustomImage ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์—ˆ๋‹ค.

import NextImage from 'next/image';
import type { ReactElement } from 'react';

type ImageProps = {
  src: string;
  alt?: string;
  width?: number;
  height?: number;
};

/**
 * ํ…Œ์ŠคํŠธ์šฉ Image ์ปดํฌ๋„ŒํŠธ
 * - src๋Š” ํ•„์ˆ˜
 * - alt ๊ธฐ๋ณธ๊ฐ’์€ ๋นˆ ๋ฌธ์ž์—ด
 */
export default function CustomImage({
  src,
  alt = '',
  width = 20,
  height = 20,
  ...rest
}: ImageProps): ReactElement {
  return <NextImage src={src} alt={alt} width={width} height={height} {...rest} />;

next/image๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. 

 

๊ทธ๋Ÿฐ๋ฐ svg, gif, apng ํ˜•์‹์€ Next.js์—์„œ ์ด๋ฏธ์ง€ ์ตœ์ ํ™”๋ฅผ ์ง„ํ–‰ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค.

์šฉ๋Ÿ‰์ด ๋งค์šฐ ์ž‘๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ƒฅ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค๊ณ ..

 

๊ทธ๋ž˜์„œ ๋ณดํ†ต ์•„์ด์ฝ˜์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ์ฐพ์•„๋ณด๋‹ˆ๊นŒ Next์—์„œ๋Š” @svgr/webpack์ด๋ผ๋Š” ์›นํŒฉ ๋กœ๋”๋ฅผ ์„ค์น˜ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

 

์•„์ด์ฝ˜์„ ๋” ์—ฌ๊ธฐ์ €๊ธฐ์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ํ›„๋‹ค๋‹ฅ ์ˆ˜์ •์„ ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.


2. @svgr/webpack

1. svg ํŒŒ์ผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค : ์ผ๋ฐ˜ /  ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ / ์›นํŒฉ ๋กœ๋”

svg ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์„ธ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

๊ทธ๋ƒฅ svg ํŒŒ์ผ์„ ๋ฐ”๋กœ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ๋ฒ•, ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ถ™์ด๋Š” ๋ฐฉ๋ฒ•, ์›นํŒฉ ๋กœ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

  ์‚ฌ์šฉ ๋ฐฉ๋ฒ• TS/React ์ธ์‹ props ์ง€์›
๊ธฐ๋ณธ svg import MyIcon from './icon.svg';
<img src={MyIcon} />
๊ทธ๋ƒฅ ๋ชจ๋“ˆ ๊ฐ์ฒด(string, any type) ๋ถˆ๊ฐ€
?react ๋ถ™์ž„ import MyIcon from './icon.svg?react';
<MyIcon width={24} height={24} />
React ์ปดํฌ๋„ŒํŠธ ๊ฐ€๋Šฅ
svgr/webpack import MyIcon from './icon.svg';
<MyIcon width={24} height={24} />
React ์ปดํฌ๋„ŒํŠธ ๊ฐ€๋Šฅ

 

React ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด svg ํŒŒ์ผ์˜ ํฌ๊ธฐ, ์ƒ‰์ƒ ๋“ฑ์„ ๋” ํŽธํ•˜๊ฒŒ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์—ฌ๊ธฐ์„œ ?react ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ถ™์ด๋ฉด ์‰ฝ๊ฒŒ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, svgr/webpack์„ ์‚ฌ์šฉํ•˜๋ฉด ์ดˆ๊ธฐ ์„ธํŒ…์ด ์ข€ ํ•„์š”ํ•˜๋‹ค.

?react์˜ ์žฅ๋‹จ์ ๊ณผ svgr/webpack์˜ ์žฅ๋‹จ์ ์„ ๋น„๊ตํ•ด๋ณด์ž.

 

?react vs svgr/webpack

  ?react svgr/webpack
๐Ÿ‘ ์žฅ์  - ํ•„์š”ํ•œ SVG๋งŒ React ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅ
- Next.js/Turbopack ํ™˜๊ฒฝ์—์„œ ์„ค์ •์ด ๊ฐ„๋‹จ
- props ์ „๋‹ฌ ๊ฐ€๋Šฅ
- ๋ชจ๋“  svg ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ React ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜
- import ๊ตฌ๋ฌธ๋งŒ ์จ๋„ ๋ฐ”๋กœ <Icon /> ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅ
- props๋ฅผ ํ†ต์ผ๋œ ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
๐Ÿ‘Ž ๋‹จ์  - import๋งˆ๋‹ค ์ผ์ผ์ด ?react ๋ถ™์—ฌ์•ผ ํ•จ
- ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์— ๊ฑธ์ณ ์ผ๊ด€๋œ ๊ทœ์น™์„ ์ ์šฉํ•˜๊ธฐ ์–ด๋ ค์›€
- ๊ธฐ์กด import ๋ฐฉ์‹๊ณผ ์„ž์ผ ์œ„ํ—˜์ด ์žˆ์Œ
- ์ดˆ๊ธฐ Webpack/Turbopack ์„ค์ • ํ•„์š”
- ํ•„์š”์—†๋Š” SVG๊นŒ์ง€ ๋ชจ๋‘ React ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜๋  ์ˆ˜ ์žˆ์Œ

 

์žฅ๋‹จ์ ์„ ๋น„๊ตํ•ด๋ณด๋ฉด svgr/webpack์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์ผ๊ด€์„ฑ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ svgr ์‚ฌ์ดํŠธ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด React ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€ svg ํŒŒ์ผ์„ ๋”ฐ๋กœ ์ง€์ •ํ•  ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

 

์ด ํ”„๋กœ์ ํŠธ๋Š” ๊ทœ๋ชจ๊ฐ€ ๊ฝค ์žˆ์œผ๋ฉฐ, ๋‚ด๊ฐ€ ์ฐพ์•„๋ณด๋ฉด์„œ ์ ์šฉํ•˜๊ณ ์‹ถ์€ ๊ฒƒ๋“ค์ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— svgr/webpack์„ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

 

2. svg/webpack ์„ค์น˜ ๋ฐ ์„ธํŒ…

svgr/webpack์€ SVG๋ฅผ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ํˆด(์›นํŒฉ ๋กœ๋”)์ด๋‹ค.

 

https://react-svgr.com/docs/what-is-svgr/

 

SVGR - Transforms SVG into React Components. - SVGR

Transforms SVG into React Components.

react-svgr.com

 

1. ์„ค์น˜ํ•˜๊ธฐ

cli์— ์ž…๋ ฅํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค์น˜ํ•ด์ค€๋‹ค.

npm install --save-dev @svgr/webpack
# yarn
yarn add --dev @svgr/webpack

 

 

2. next.config.js ์„ธํŒ… ( turbopack ์‚ฌ์šฉ ์‹œ )

๊ณตํ™ˆ์—์„œ๋Š” webpack setting์„ ์•Œ๋ ค์ฃผ๋Š”๋ฐ, turbopack์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๊ทธ๊ฑฐ ์—๋Ÿฌ๋‚œ๋‹ค.

์•„๋ž˜ ๋‚ด์šฉ๋งŒ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // svg in turbopack setting
  turbopack: {
    rules: {
      '*.svg': {
        loaders: ['@svgr/webpack'],
        as: '*.js',
      },
    },
  },
};

export default nextConfig;

 

3. svgr.d.ts & tsconfig.json ์„ธํŒ… ( TypeScript ์‚ฌ์šฉ ์‹œ )

TypeScript๋Š” ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ ํƒ€์ž…์„ ์•Œ์•„์•ผ ํ•˜๋Š”๋ฐ svg ํŒŒ์ผ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํƒ€์ž… ์ •๋ณด๊ฐ€ ์—†๋‹ค.

๋”ฐ๋ผ์„œ svgr.d.ts์— svg ํŒŒ์ผ์˜ ํƒ€์ž…์„ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.

// svgr.d.ts
declare module '*.svg' {	// .svg ํ™•์žฅ์ž๋ฅผ ๊ฐ€์ง„ ๋ชจ๋“  ํŒŒ์ผ์€ ์ด ๋ชจ๋“ˆ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง์„ ์„ ์–ธ
  import React from 'react';	// ์ด ๋ชจ๋“ˆ์˜ ํƒ€์ž…์€ React์˜ ํƒ€์ž…
  // React.FC.. : ๋ฐ˜ํ™˜๊ฐ’์ด ์—†๊ณ  children์„ ๋ฐ›์ง€ ์•Š๋Š” React ์ปดํฌ๋„ŒํŠธ
  // React.SVG.. : ์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” props ํƒ€์ž… (SVG ๊ธฐ๋ณธ ์†์„ฑ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ)
  const SVG: React.FC<React.SVGProps<SVGSVGElement>>;
  export default SVG;
}

 

svgr.d.ts ๊ฐ™์€ ๋ชจ๋“ˆ ์„ ์–ธ ํŒŒ์ผ์€ TypeScript๊ฐ€ ํ”„๋กœ์ ํŠธ๋ฅผ ์ปดํŒŒ์ผํ•  ๋•Œ ๊ฐ€์žฅ ๋จผ์ € ์ฐธ์กฐํ•ด์•ผํ•œ๋‹ค. ๋”ฐ๋ผ์„œ svgr.d.ts๋ฅผ ๊ฐ€์žฅ ๋จผ์ € include ํ•˜๋„๋ก tsconfig.json์„ ์ž‘์„ฑํ•œ๋‹ค.

// tsconfig.json
...
"include": ["svgr.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]

 

4. .storybook/main.ts ์„ธํŒ… ( storybook ์‚ฌ์šฉ ์‹œ )

์ด๊ฑด ๋’ค์— ์ž‘์„ฑ

 


3. ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ ๊ณผ์ •

ํ•„์š”ํ•œ ํŒŒ์ผ๋“ค์„ ๋ชจ๋‘ ์ž‘์„ฑํ–ˆ์œผ๋‹ˆ ์ด์ œ SVG ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•˜๋„๋ก ์„ธํŒ…ํ•  ๊ฑฐ๋‹ค.

์ด ์ƒํƒœ๋กœ SVG ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฐ ๋ฐฉ์‹์ด ๋  ๊ฒƒ์ด๋‹ค.

import MyIcon from './MyIcon.svg';

...

<MyIcon className="..." width={24} height={24} />

 

์ง€๊ธˆ๋„ ์ถฉ๋ถ„ํžˆ ์‚ฌ์šฉํ•˜๊ธฐ์— ์ข‹์ง€๋งŒ ์ปดํฌ๋„ŒํŠธํ™” ํ•˜์—ฌ ์†์„ฑ์„ ์ข€ ๋” ์ผ๊ด€์„ฑ์žˆ๊ฒŒ, ์ž์œ ๋กญ๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

 

1. svg ํŒŒ์ผ๋“ค ์ˆ˜์ •

์šฐ์„  svg ํŒŒ์ผ์— ๊ณ ์ •๊ฐ’์ด ๋“ค์–ด๊ฐ€์žˆ๋Š” width, height, fill ์„ ๋ชจ๋‘ current๋กœ ๋ฐ”๊ฟ”์ฃผ์–ด์•ผ ๋งˆ์Œ๋Œ€๋กœ ์ € ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.7071 14.2929C12.3166 14.6834 11.6834 14.6834 11.2929 14.2929L8.70711 11.7071C8.07714 11.0771 8.52331 10 9.41421 10H14.5858C15.4767 10 15.9229 11.0771 15.2929 11.7071L12.7071 14.2929Z" fill="black"/>
</svg>

<svg width="current" height="current" viewBox="0 0 24 24" fill="current" xmlns="http://www.w3.org/2000/svg">
<path d="M12.7071 14.2929C12.3166 14.6834 11.6834 14.6834 11.2929 14.2929L8.70711 11.7071C8.07714 11.0771 8.52331 10 9.41421 10H14.5858C15.4767 10 15.9229 11.0771 15.2929 11.7071L12.7071 14.2929Z" fill="current"/>
</svg>

 

2. icons.ts ์ž‘์„ฑ : ์ปดํฌ๋„ŒํŠธ import

์‹ค์ œ SVG ์ปดํฌ๋„ŒํŠธ๋ฅผ importํ•˜๊ณ , ํƒ€์ž…ํ™”ํ•˜๋Š” icons.ts๋ฅผ ์ž‘์„ฑํ•ด์ค€๋‹ค.

// SVG ์•„์ด์ฝ˜ import
import IC_AllLink from './svgs/all_link.svg';
import IC_ArrowdropDown from './svgs/arrowdrop_down.svg';
import IC_ArrowdropLeft from './svgs/arrowdrop_left.svg';

// ์ปดํฌ๋„ŒํŠธ๋“ค๋กœ IconMap ๊ตฌ์„ฑ
export const IconMap = {
  IC_AllLink,
  IC_ArrowdropDown,
  IC_ArrowdropLeft,
} as const;

// IconMapTypes = 'IC_Alllink' | 'IC_ArrowdropDown' | 'IC_ArrowdropLeft' | ...
export type IconMapTypes = keyof typeof IconMap;

// ์‚ฌ์ด์ฆˆ ๊ตฌ์„ฑ
export const IconSizes = {
  sm: 16,
  md: 20,
  lg: 24,
};

// IconSizeTypes = 'sm' | 'md' | 'lg' | ...
export type IconSizeTypes = keyof typeof IconSizes;

 

 

3. SVGIcon.tsx ์ž‘์„ฑ : ์‹ค์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ

์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹ค์ œ ์•„์ด์ฝ˜์ด ํ•„์š”ํ•œ ๊ณณ์—์„œ ์‚ฌ์šฉํ•  ๊ฑฐ๋‹ค.

import React from 'react';
import { IconMap, IconMapTypes, IconSizeTypes, IconSizes } from './icons';

// icons.ts์—์„œ ์ •์˜ํ•œ IconMapTypes, IconSizeTypes๋ฅผ ๊ฐ๊ฐ icon, size์˜ ํƒ€์ž…์œผ๋กœ ์ •์˜
export interface SVGIconProps {
  icon: IconMapTypes;
  size?: IconSizeTypes;
  className?: string;
}

const SVGIcon: React.FC<SVGIconProps> = ({ icon, size = 'lg', className }: SVGIconProps) => {
  // <SVGIcon icon={'IC_ALLlink'} -> Icon = IconMap[IC_Alllink]
  const Icon = IconMap[icon as IconMapTypes];

  if (!Icon) return null;

  return <Icon className={className} width={IconSizes[size]} height={IconSizes[size]} />;
};

export default SVGIcon;

 

 


4. storybook ์—๋Ÿฌ

์Šคํ† ๋ฆฌ๋ถ์ด ์‹œํ—˜ํ•ด๋ณด๊ธฐ ๊ฐ„๋‹จํ•˜๋‹ˆ๊นŒ ์Šคํ† ๋ฆฌ๋ถ์—์„œ ๋จผ์ € ์‹œํ—˜ํ•ด๋ดค๋Š”๋ฐ ์•„๋ฌด๋ฆฌ ์ด๊ฒƒ์ €๊ฒƒ ์ˆ˜์ •ํ•ด๋„ ๊ณ„์† ์—๋Ÿฌ๊ฐ€ ๋œจ๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋‹ค๊ฐ€ SVGIcon๋งŒ ์‚ฌ์šฉํ•ด๋ณด๊ณ , IconButton์„ ์‚ฌ์šฉํ•ด๋ณด๋‹ˆ๊นŒ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ณด๊ณ  '์•„ ๋˜ ์Šคํ† ๋ฆฌ๋ถ์ด๊ตฌ๋‚˜..!' ํ•˜๋ฉด์„œ ์ฐพ์•˜๋‹ค.

์˜ค๋Š˜๋„ ํ—ค๋ฉ”๋А๋ผ ๊ฝค ๋งŽ์€ ์‹œ๊ฐ„์„ ๋‚ ๋ฆฐ ๋‚˜..

 

๊ฒฐ๋ก ์€ ์Šคํ† ๋ฆฌ๋ถ์€ ์ž์ฒด webpack์„ ์‚ฌ์šฉํ•ด์„œ ๋‚ด๊ฐ€ ์—ด์‹ฌํžˆ ์„ธํŒ…ํ•œ turbopack ์„ค์ •๋“ค์ด ์•ˆ๋จนํžŒ๋‹ค๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. -.-

๊ทธ๋ž˜์„œ ์Šคํ† ๋ฆฌ๋ถ์šฉ svg loader๋ฅผ ๋”ฐ๋กœ ์„ธํŒ…ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

.storybook/main.ts

import type { StorybookConfig } from '@storybook/nextjs';
import type { RuleSetRule } from 'webpack';	// webpack์˜ module.rules ๋ฐฐ์—ด์— ๋“ค์–ด๊ฐ€๋Š” ํ•ญ๋ชฉ ํƒ€์ž…์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•จ

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-onboarding',
    '@chromatic-com/storybook',
    '@storybook/experimental-addon-test',
  ],

  framework: {
    name: '@storybook/nextjs',
    options: {},
  },
  staticDirs: ['../public'],

  // ์ถ”๊ฐ€๋กœ ์ž‘์„ฑํ•œ ๋ถ€๋ถ„
  webpackFinal: async config => {  // ์ตœ์ข… webpack ์„ค์ •์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๋Š” ํ•จ์ˆ˜
    if (!config?.module?.rules) return config; // config๊ฐ€ undefined์ด๊ฑฐ๋‚˜ ์—†์œผ๋ฉด ๋ฐ˜ํ™˜
    const rules = config.module.rules as RuleSetRule[];  config.module.rules ํƒ€์ž… ์„ ์–ธ (์ด ๋ฐฐ์—ด์€ RuleSetRule[] ํƒ€์ž…์ž„)

    config.module.rules = rules.map(rule => {  // ๊ธฐ์กด rules ๋ฐฐ์—ด์„ map์œผ๋กœ ์ˆœํšŒํ•˜๋ฉฐ ๊ทœ์น™ ์ˆ˜์ •
      // test๊ฐ€ ์ •๊ทœ์‹์ธ๊ฐ€ && ํ•ด๋‹น ์ •๊ทœ์‹์— svg ๋ฌธ์ž์—ด์ด ํฌํ•จ๋˜์—ˆ๋Š”๊ฐ€
      if (rule.test instanceof RegExp && /\.svg\b/.test(rule.test.toString())) {
        // ๊ธฐ์กด rule์„ ๋ณต์‚ฌํ•˜์—ฌ exclude๋ฅผ ์ถ”๊ฐ€
        // exclude : ์ด rule์—์„œ svg๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋‹ค๋ฅธ ํŒŒ์ผ๋งŒ ์ฒ˜๋ฆฌ (๊ธฐ์กด file-loader๊ณผ์˜ ์ถฉ๋Œ ๋ฐฉ์ง€)
        return { ...rule, exclude: /\.svg$/i };
      }
      return rule;
    });

 

 


5. ๊ฒฐ๊ณผ๋ฌผ

๋กœ์ปฌ ํ˜ธ์ŠคํŠธ ํ™”๋ฉด

 

์Šคํ† ๋ฆฌ๋ถ ํ™”๋ฉด

 

 

 

๊ทธ๋ž˜๋„ ๊น”๋”ํ•˜๊ฒŒ ์™„์„ฑํ•ด์„œ ๊ธฐ๋ถ„์ด ์ข‹๋‹ค. ํœด~

 

 

 

์ฐธ๊ณ 

๋”๋ณด๊ธฐ

svg ์•„์ด์ฝ˜์˜ ๊ฒฝ์šฐ์—๋„ image ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉํ•ด์•ผํ•˜๋‚˜์š”?

 

svg ์•„์ด์ฝ˜์˜ ๊ฒฝ์šฐ์—๋„ image ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉํ•ด์•ผํ•˜๋‚˜์š”? - ์ธํ”„๋Ÿฐ | ์ปค๋ฎค๋‹ˆํ‹ฐ ์งˆ๋ฌธ&๋‹ต๋ณ€

๋ˆ„๊ตฌ๋‚˜ ํ•จ๊ป˜ํ•˜๋Š” ์ธํ”„๋Ÿฐ ์ปค๋ฎค๋‹ˆํ‹ฐ. ๋ชจ๋ฅด๋ฉด ๋ฌป๊ณ , ํ•ด๋‹ต์„ ์ฐพ์•„๋ณด์„ธ์š”.

www.inflearn.com

Next.js-Components-Images

 

Components: Image | Next.js

Optimize Images in your Next.js Application using the built-in `next/image` Component.

nextjs.org

https://react-svgr.com/docs/webpack/

 

SVGR - Transforms SVG into React Components. - SVGR

Transforms SVG into React Components.

react-svgr.com

https://sihun.dev/blog/nextjs15_svgr_setting

 

Next.js 15 + SVGR ์„ธํŒ… ๋ฐฉ๋ฒ• (feat.TurboPack)

Next.js 15์—์„œ TurboPack๊ณผ webpack์„ ์„ค์ •ํ•ด์„œ SVGR์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด…์‹œ๋‹ค

sihun.dev

https://stackoverflow.com/questions/79329145/how-to-import-svg-icons-in-nextjs-15

 

How to import svg icons in Nextjs 15

I downloaded the Vercel Ecommerce template and want to use it with custom icons. I have installed @svgr/webpack and configured next.config.mjs: export default { images: { formats: ['image/avi...

stackoverflow.com

https://nextjs.org/docs/app/api-reference/config/next-config-js/turbopack#examples

 

next.config.js: turbopack | Next.js

Configure Next.js with Turbopack-specific options

nextjs.org

https://bh2980.tistory.com/276

 

Next.js์™€ Storybook์— SVGR ์„ค์ •ํ•˜๊ธฐ

ํ”„๋กœ์ ํŠธ์™€ Storybook์— SVGR ์„ค์ •ํ•˜๊ธฐ ์น˜์Šคํ†ก ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ SVGR์„ ์‚ฌ์šฉํ•ด์•ผํ•  ์ผ์ด ์ƒ๊ฒผ๋‹ค. ์˜ค๋Š˜์€ Next.js๊ธฐ๋ฐ˜ ํ”„๋กœ์ ํŠธ์™€ Storybook์— SVGR์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ ์–ด๋ณด๋ คํ•œ๋‹ค. SVGR์ด๋ž€? SVG๋Š”

bh2980.tistory.com

https://velog.io/@jh5414092/SVG-Icon-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0SVGR-TS

 

SVG Icon ์ปดํฌ๋„ŒํŠธ๋กœ ๋งŒ๋“ค๊ธฐ(SVGR, TS)

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ svg ํŒŒ์ผ์„ ์“ธ ์ผ์ด ๋˜๊ฒŒ ๋งŽ์€๋ฐ ๋‚˜๋Š” svg ํŒŒ์ผ์„ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค svgr lib๋ฅผ ์‚ฌ์šฉํ•ด์™”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ icon์€ ์‚ฌ์ด์ฆˆ๋‚˜ ์ƒ‰์ƒ์ด ์ •ํ•ด์ ธ์„œ ์žฌ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•˜์—ˆ๋‹ค.

velog.io

 

 

 

๋ฐ˜์‘ํ˜•