프린세스 다이어리

[Storybook] 스토리북에서 vue svg파일 import 하는법 본문

FE

[Storybook] 스토리북에서 vue svg파일 import 하는법

개발공주 2022. 1. 27. 22:34
728x90

1. 문제상황

컴포넌트를 개발하기 이전에 스토리북을 짜는 게 아니라, 이미 개발한 공통 컴포넌트를 기반으로 스토리북 독스를 작성하는 상황이다.

 

우리 스토리북 프로젝트는 모노레포로 구성돼 있어, 스토리북 자체 stories 레포와 vue 공통 컴포넌트만을 가지고 있는 component 레포가 함께 있다. component 레포의 vue 파일을 끌어다가 stories 레포에서 문서를 작성하는 특이한 상황이라, svg 파일이 쉽사리 import 되지 않아 세팅에 시간을 좀 들이게 됐다.

storybook
  - node_modules
  - stories
    - node_modules
    - package.json
  - components
    - node_modules
    - package.json
  - package.json
  - yarn.lock

 

2. 해결방법

구글에서 공식문서들과 수많은 스택오버플로우 글을 보면서 정말 다양한 방법으로 svg 파일을 가져와 봤는데, 결국 우리 프로젝트에서는 기존 프로젝트에서 svg 파일을 import하기 위해 vue-svg-loader를 사용했었기 때문에 스토리북에서도 마찬가지로 vue-svg-loader를 사용하도록 설정해줘야 한다.

// main.js

const path = require('path');

module.exports = {
    stories: [
        '../**/*.stories.@(js|jsx|ts|tsx)',
        '../components/**/*.stories.mdx',
    ],
    addons: [
        '@storybook/addon-links',
        '@storybook/addon-actions',
        '@storybook/addon-essentials',
    ],
    webpackFinal: async (config, {configType}) => {
        // ...
        
        const svgRule = config.module.rules.find((rule) =>
            rule.test.test('.svg'),
        );
        svgRule.test = /\.(png|jpe?g|gif|webp)$/;
        config.module.rules.push({
            test: /\.svg$/,
            use: ['vue-loader', 'vue-svg-loader'],
        });

        return config;
    },
};

 

여기서 이 부분을 설명해보자면, 기존 스토리북에서 svg 파일을 import하기 위해서 file-loader 라는 것을 사용하고 있는데, 이 rule에서 svg설정을 찾아서 vue-loader와 vue-svg-loader를 사용하도록 넣어주라는 의미다. 

const svgRule = config.module.rules.find((rule) =>
    rule.test.test('.svg'),
);
svgRule.test = /\.(png|jpe?g|gif|webp)$/;
config.module.rules.push({
    test: /\.svg$/,
    use: ['vue-loader', 'vue-svg-loader'],
});

 

오랫동안 헤맸던 이유는 해당 프로젝트가 Nuxt 기반 프로젝트도 아니라서 문서에 Nuxt.js 프로젝트에서 어떻게 vue-svg-loader를 적용할지 쓰여 있음에도 가볍게 패스했기 때문이다ㅎㅋ 출처는 https://www.npmjs.com/package/vue-svg-loader 여기다. 동료의 도움으로 해결하게 됐다.

 


3. 삽질기록

해결하기까지 어떤 시도를 했는지 기록하려고 한다.

 

실패1

    const assetRule = config.module.rules.find(({ test }) => test.test('.svg'));

    const assetLoader = {
      loader: assetRule.loader,
      options: assetRule.options || assetRule.query,
    };

    config.module.rules.unshift({
      test: /\.svg$/,
      use: ['@svgr/webpack', assetLoader],
    });

-> DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('000000.svg') is not a valid name. 에러

 

실패2

  const fileLoaderRule = config.module.rules.find(rule => rule.test.test('.svg'));
  fileLoaderRule.exclude = /\.svg$/;
  config.module.rules.push({
    test: /\.svg$/,
    use: ["@svgr/webpack", "url-loader"],
  });

-> @svgr/webpack + url-loader 되려나 했는데 안됨.

-> 위에 exclude 경우 svg 자체가 unexpected token.

 

실패3

  const rules = config.module.rules;

  // modify storybook's file-loader rule to avoid conflicts with your inline svg
  const fileLoaderRule = rules.find(rule => rule.test.test('.svg'));
  fileLoaderRule.exclude = /\.inline.svg$/;

-> DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('000000.svg') is not a valid name. 에러

 

실패4

    const rules = config.module.rules;
    const fileLoaderRule = rules.find((rule) => rule.test.test('.svg'));
    fileLoaderRule.exclude = /\.svg$/;

    rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });

    return config;

-> DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('000000.svg') is not a valid name. 에러

 

실패5

    // 스토리북에 디폴트로 적용되는 file-loader rule에서 svg 설정을 찾아 삭제한다.
    const rules = config.module.rules;
    const fileLoaderRule = rules.find((rule) => rule.test.test('.svg'));
    fileLoaderRule.exclude = /\.svg$/;

    // svg 관련 기존 로더 rule을 삭제 후, @svgr/webpack를 적용한다.
    rules.push({
      test: /\.svg$/,
      exclude: /node_modules/,
      use: ['@svgr/webpack'],
    });

-> VNode 워닝 해결 못하고 아이콘 안 뜸 

 

실패6

    config.module.rules.unshift({
      test: /\.svg$/,
      exclude: /node_modules/,
      loader: ['vue-svg-loader'], 
    });

-> ERROR in ../000000.svg

-> Module build failed (from ./node_modules/vue-svg-loader/index.js):

-> Error: Cannot find module 'vue-template-compiler'

-> 그럼 vue-template-compiler의 종속 라이브러리 전부 다운받으면 될까? 시도해봄. vue@3.2.26, vue-template-compiler@^2.6.14

-> 안됨

728x90
Comments