[@svgr/webpack] Next.SVG를 js/Storybook에서 어셈블리로 처리

하고 싶은 일

  • SVG 파일을 창고에 저장하고 React 구성 요소에서 처리하기를 원합니다
  • Next.js와 Storybook 두 개로 표시하고 싶습니다
  • 문장 요약


  • @svgr/webpack를 이용하여 웹 패키지의 설정을 작성하고 해결
  • Next.js로 표시하면 간단하지만 Storybook에 함정이 많다
  • 사전 요구 사항 정보

  • Next.js제로 필자의 개인 블로그 실시: https://github.com/MH4GF/log.mh4gf.dev
  • 이 글의 전신 스크랩에 업무일지를 기재했다: https://zenn.dev/mh4gf/scraps/57b84180a70ae7
  • 본 문서의 최종 결과 제출 로그는 Pull Request: https://github.com/MH4GF/log.mh4gf.dev/pull/70
  • Next.js에 표시


    먼저 추가@svgr/webpack.
    yarn add -D @svgr/webpack
    
    다음에 next.config.js에 웹 패키지 설정을 추가합니다.
    // next.config.js
    
    module.exports = {
      ~~~ 省略 ~~~
      webpack: (config) => {
        config.module.rules.push({
          test: /\.svg$/,
          use: ['@svgr/webpack'],
        })
        return config
      },
    }
    
    SVG 파일을 저장하고 적절한 구성 요소로 import을 하고 JSX를 추가합니다.
    import ExternalLinkIcon from '~/src/assets/svg/external-link.svg'
    
    const App = () => (
      <div>
        <ExternalLinkIcon />
      </div>
    )
    
    이것만 Next입니다.SVG는 js를 통해 표시할 수 있습니다.

    Storybook에 표시

    ./storybook/main.js에도 웹 패키지 설정이 추가되었습니다.
    // ./storybook/main.js
    
      webpackFinal: async (config) => {
        ~~ 省略 ~~
        config.module.rules.push({
          test: /\.svg$/,
          use: ['@svgr/webpack'],
        })
    
        return config
      },
    
    이 상태에서 Storybook 구축을 수행할 때TypeError: this.getOptions is not a function 발생합니다.
    ERR! => Failed to build the preview
    ERR! ./src/assets/svg/external-link.svg
    ERR! Module build failed (from ./node_modules/@svgr/webpack/dist/index.js):
    ERR! TypeError: this.getOptions is not a function
    ERR!     at Object.svgrLoader (/home/runner/work/log.mh4gf.dev/log.mh4gf.dev/node_modules/@svgr/webpack/dist/index.js:83:24)
    ERR!  @ ./src/components/ArticleListItem/index.tsx 2:0-66 24:33-49
    ERR!  @ ./src/components/ArticleListItem/index.stories.tsx
    ERR!  @ ./src sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx))$
    ERR!  @ ./generated-stories-entry.js
    

    TypeError: this.getOptions is not a function


    이 문제는 Webpack5로 수정하면 해결됩니다.ref:
    https://github.com/gregberge/svgr/issues/631
    Storybook에서 Webpack5를 사용하는 문서에 따라 업그레이드합니다.
    yarn add --dev @storybook/builder-webpack5 @storybook/manager-webpack5
    
    // ./storybook/main.js
    module.exports = {
      core: {
        builder: 'webpack5',
      },
      ~~~ 省略 ~~~
    
    이렇게 하면 this.getOptions 오류가 발생하지 않지만 다음과 같은 오류가 발생한다.
    $ yarn storybook
    yarn run v1.22.11
    $ start-storybook -p 6006
    info @storybook/react v6.4.22
    info 
    info => Loading presets
    info => Serving static files from ././public at /
    info => Using PostCSS preset with [email protected]
    info => Using default Webpack5 setup
    <i> [webpack-dev-middleware] wait until bundle finished
    9% setup compilation DocGenPlugininternal/modules/cjs/loader.js:905
      throw err;
      ^
    
    Error: Cannot find module 'webpack/lib/util/makeSerializable.js'
    

    Cannot find module 'webpack/lib/util/makeSerializable.js'


    이것은 아래 issue의 업무 복습을 통해 해결되었다.ref:
    https://github.com/storybookjs/storybook/issues/15336#issuecomment-906809203
    ./storybook/main.다음과 같이 js를 수정합니다.
    // ./storybook/main.js
    module.exports = {
      ~~~ 省略 ~~~
      typescript: { reactDocgen: false },
    }
    
    Storybook의 Webpack5는 아직 experimental에 대응하기 때문에 어쩔 수 없다고 생각합니다.
    이렇게 구축하면 통과할 수 있지만 SVG에서 import 구성 요소의 story를 표시하는 중 오류가 발생했습니다.
    Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/external-link.981294d1.svg') is not a valid name.
    

    Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/external-link.981294d1.svg') is not a valid name.


    이 오류는 Storybook에서 기본적으로 준비한 웹 패키지의 설정으로svg의 확장자가 file-loader에 불러오기 때문입니다.
    https://github.com/storybookjs/storybook/issues/9070
    그거 취소로 설정하면 해결될 거야.
      webpackFinal: async (config) => {
        ~~ 省略 ~~
        const fileLoaderRule = config.module.rules.find((rule) => rule.test && rule.test.test('.svg'))
        fileLoaderRule.exclude = /\.svg$/
    
        return config
      },
    
    Storybook은 위의 몇 가지 대응에 따라 SVG를 표시할 수도 있습니다.

    끝맺다


    이미 주기적인 방법으로 해결했기 때문에 향후 관련 프로그램 라이브러리의 업데이트를 추적하고 싶습니다.이 보도에 대한 선전도 매우 환영한다.
    이번에 사용한 것은 @svgr/webpack,넥스트다.나는 js와 Storybook에서 Webpack의 설정이 다르다는 것에 매우 신경을 쓴다.웹팩으로 복잡한 일을 하면 바이트 환승 등도 어려워지기 때문에 가능하면 최소한으로 컨트롤하고 싶다.
    더 좋은 선택이 있다면 다른 방법을 바꾸고 싶습니다.

    좋은 웹페이지 즐겨찾기