카테고리 없음

Storybook에서 svg 사용하기

합주기 2025. 5. 1. 02:29

svg 아이콘을 포함한 컴포넌트의 스토리북을 만들때 반드시 오류가 난다.

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

 

👉 "엘리먼트 타입이 유효하지 않습니다: (기본 내장 컴포넌트의 경우) 문자열이거나 (합성 컴포넌트의 경우) 클래스나 함수여야 하는데, 객체를 받았습니다."

 

Icon을 컴포넌트처럼 사용하고 있는데, <Icon /> 에서 Icon이 클래스나 함수여야 하지만, 객체라서 컴포넌트로 만들수 없다. 즉 엘리먼트 타입이 유효하지 않다는 오류가 나온것이다.

 

webpack은 .svg 파일을 보면 기본적으로 파일 경로를 문자열로 반환하거나, file-loader/url-loader 설정에 따라 객체로 변환합니다.

 

해결

storybook에서 svg 처리하는 방식을 지정해주면된다.

이전에 svg를 import 해서 컴포넌트 방식을 사용하기 위해 “@svgr/webpack 을 사용했었다.

 

next.config.ts 에 적용하듯이, .storybook/main.ts에 웹펙 설정부분을 추가한다.

import type { StorybookConfig } from "@storybook/nextjs";

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을 통해 Webpack 설정을 변경
  webpackFinal: async (config) => {
    if (!config.module || !config.module.rules) {
      return config;
    }

    config.module.rules = [
      ...config.module.rules.map((rule) => {
        if (!rule || rule === "...") {
          return rule;
        }

        if (rule.test && /svg/.test(String(rule.test))) {
          return { ...rule, exclude: /\.svg$/i };
        }
        return rule;
      }),
      {
        test: /\.svg$/,
        use: ["@svgr/webpack"],
      },
    ];

    return config;
  },
};
export default config;

 

해석하자면 다음과 같다.

module의 rules 배열을 순회하면서, 해당 rule에 exclude: /\\.svg$/i 를 적용한다.

즉 file-loader가 svg 모듈을 무시하도록 한다.

그 후에 새로운 file-loader > “@svgr/webpack” 을 추가한다.

 

참고

https://cheolsker.tistory.com/81