티스토리 뷰

사이드 프로젝트/🩺 바디토리 : 건강기록 및 병원추천 웹서비스

svgr과 lottie를 함께 사용하니 발생했던 이슈

2022. 12. 13. 15:00

👿 이슈상황

 

로컬에서 웹 서비스 전체 개발 작업을 마치고, build하여 VM에 배포한 후 테스트를 하던 중 lottie를 적용한 애니메이션 일부가 제대로 보여지지 않는 것을 발견하였다.

정상적으로 보여져야하는 lottie 애니메이션 / 오류가 발생한 lottie 애니메이션

 

 

다른 lottie 애니메이션 요소들도 위와 같이 애니메이션의 몇몇 부분이 나타나지 않는 상황을 확인하였다.

 

로컬에서 개발할 때는 문제가 없었어서 다시 한번 확인해보니 로컬에서 서비스를 실행할 때는 정상적으로 보여지는데 

build 후 배포 시에만 위와 같은 이슈가 발생하였다.

 

 

 

 

 

 

 

💡 해결과정

 

1) 브라우저 콘솔에서 svg요소가 제대로 들어왔는지 및 에러메세지 확인하기

 

우선 안보이는 부분들이 svg 자체가 생성되지 않아서 안보이는건지 

svg는 생성이 되었는데 애니메이션이 동작하는 과정에서 안보이게된지 확인해보기 위해 브라우저 콘솔에서 확인을 해보았다.

 

아래와 같이 제대로 보이지 않는 svg의 특정 path 요소들이 에러가 찍히고 있었다.

 

 

 

에러가 나는 path들을 찾아보니 위의 에러메세지처럼 빌드 후에는 path의 경로(d)가 이상한 것을 발견하였다.

 

// 빌드 전 path의 경로(d)
<path d=" M18.13599967956543,0.0010000000474974513 C18.13599967956543,..." ... />

// 빌드 후 path의 경로(d)
<path d=" C18.13599967956543,..." ... />

 

 

에러 메세지로 구글링을 해본 결과, 나의 이슈를 해결하는데 도움이 될만한 내용은 못찾았다.

 

 

 

 

 

2) lottie를 직접 만드는 과정에서 문제가 있었나 확인하기

 

SVG 자체는 들어오고 있는데 그안의 path가 제대로 들어오지 않는 부분에 대해서,

 

처음에는 에프터이펙트를 이번에 처음 써봐서 lottie 파일을 만드는 과정에서 설정을 잘못한건가 했지만

공식홈페이지에서 다운받은 lottie도 빌드 후 같은 현상이 발생했다.

 

그러므로, lottie를 잘못 만든 것보단 build 시 문제가 발생하는 것일 확률이 높다고 판단하고 build할 때

svg에 영향을 주는 것이 무엇이 있나 찾아보았다.

 

 

 

 

 

3) 빌드 시 svg와 관련된 부분이 있는지 확인하기

 

빌드와 관련해서는 아직 잘 모르는 부분이 많아서 우선은 next.js에서 빌드할 때 사용되는 next.config.js 파일을 살펴보았다.

module.exports = {
  webpack: config => {
    config.module.rules.push({
      test: /\.svg$/,
      use: ["@svgr/webpack"],
    });
    return config;
  },
  images: {
    domains: ["imagedelivery.net"],
  },
};

 

파일을 열자마자 svg라는 단어가 딱 보였다.

 

이번 프로젝트에서 svg를 컴포넌트화하여 사용하기 위해 SVGR을 사용하고 있는 것은 알고 있었지만

어떻게 적용되는지는 모르고 있었는데 위 코드를 보니 build 시 webpack의 설정을 변경하고 있는 것 같았다.

 

next.config.js 파일을 확인하고나니 빌드 시 svg에 에러가 생기는건

SVGR의 영향일 확률이 매우 높다고 생각되어 관련하여 구글링을 해보았다.

 

 

꽤나 최근에 next.js의 github에서 나와 유사한 이슈를 다룬 것을 발견하였다.

 

SVGs (specifically Lottie file SVG json) not rendering properly in 13.0.3 · Issue #42801 · vercel/next.js

Verify canary release I verified that the issue exists in the latest Next.js canary release Provide environment information Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Ver...

github.com

 

 

이 이슈는 SVGR을 사용할 때 나타난 문제는 아니지만 문제상황이 나와 비슷해서 저 글에 나와있는 해결방법들을 시도해 보았다.

 

 

 

 

해결방법1)

next.config.js에 swcMinify: false 추가하기

 

현재 우리 프로젝트에서 사용하고 있는 next.js는 13.0.3버전으로 SWC Minifier가 기본으로 활성화되어있다고 한다. 

그래서 next.config.js에 swcMinify: false 를 추가하여 SWC Minifier를 비활성화 시키는 방법을 시도해보았다.

module.exports = {
  webpack: config => {
    config.module.rules.push({
      test: /\.svg$/,
      use: ["@svgr/webpack"],
    });
    return config;
  },
  images: {
    domains: ["imagedelivery.net"],
  },
  swcMinify: false,	// 해당 부분 추가
};

 

하지만 이 방법으로는 문제가 해결되지않았다.

이 방법은 next.js의 버전에 따른 문제였는데 이 방법으로 해결이 되지 않은 것을 보면 SVGR 때문일 확률이 더 올라간 것 같다.

 

 

 

 

해결방법2)

lottie를 svg로 렌더하지않고 canvas로 렌더하기

 

next.js의 깃헙에 있던 또 다른 방법은 lottie의 renderer를 svg로 설정하지 말고 canvas로 설정하는 방법이었다.

// 기존코드

useEffect(() => {
    const chart = lottie.loadAnimation({
      container: chartRef.current,
      renderer: "svg",
      loop: true,
      autoplay: true,
      animationData: ChartAnimation,

 

//  수정한 코드

useEffect(() => {
    const chart = lottie.loadAnimation({
      container: chartRef.current,
      renderer: "canvas",
      loop: true,
      autoplay: true,
      animationData: ChartAnimation,

 

 

위와 같이 lottie 애니메이션을 설정해줄때 renderer를 canvas로 설정하니 모든 lottie 애니메이션들이 정상적으로 작동하는 것을 확인할 수 있었다.

 

 

이때까지만 해도 이렇게 이번 이슈가 해결되는 것 같았으나...

 

 

다른 lottie들도 모두 canvas로 렌더하도록 변경한 후 빌드하고 VM에 배포시켜 여러 페이지들을 계속 돌아다니면서

서비스를 전체적으로 검수하는데 화면 전환이 버벅일 때도 있었고, 어느정도 페이지 이동을 한 후에는

브라우저가 완전히 멈추는 현상이 발생하였다.

 

이전까지는 아무리 여러 페이지를 돌아다녀도 이렇게 브라우저가 멈추는 현상이 발생하지 않았었는데

lottie의 renderer를 canvas로 바꾼 뒤부터 발생한 문제인 것 같았다.

 

 

브라우저 콘솔의 performance 등을 활용하는 법을 공부해서 이런저런 분석을 해보고 싶었지만,

현재 상황에서는 프로젝트 일정이 얼마 남지않아 기간 내에 정상적인 서비스로 만드는 것이 먼저이기 때문에

당장 발견한 이슈를 해결할 수 있는 방법을 모색해보았다.

 

canvas는 다뤄본 적이 없어서 어떻게 해야할지 방법을 찾기가 어려웠다.

 

canvas를 최적화하는 방법 등을 구글링해보다가 canvas와 관련된 내용은 아니지만 초기에 발생한 svg문제를 위해

시도해볼 수 있는 방법을 한가지 더 찾게 되었다.

 

TIL: React+Webpack에서 SVGR을 사용할 때 SVG 최적화 막기

상황

driip.me

 

 

이 글의 내용을 보면 SVGR은 svg 최적화를 위해 SVGO를 사용하고 있는데 이 SVGO에서

일부 도형을 path로 바꿔버리는 등의 작업이 이루어져서 svg 애니메이션이 제대로 동작하지 않는다는 것이다.

 

 

이 방법을 시도해보기 위해 lottie의 renderer를 다시 svg로 수정하였다.

그리고 SVGR은 사용하면서 SVGO 옵션은 사용하지 않기위해 next.config.js 파일을 아래와 같이 수정해주었다.

// 수정 전
// ...
      use: ["@svgr/webpack"],
// ...
// 수정 후
//...
      use: [{ loader: "@svgr/webpack", options: { svgo: false } }],
//...

 

 

이렇게 수정하니 초기에 발생했던 svg 애니메이션이 제대로 보이지 않는 문제는 해결되었다!

페이지 이동 시 화면이 버벅거리는 현상도 이전에 비해 줄어들었다..!

 

하지만, 여러 페이지를 검수하보면 발생하는 브라우저 멈춤 현상은 여전히 지속되었다.

lottie의 renderer에 따른 문제가 아니라 lottie를 사용한다는 자체에서 발생하는 문제인 것 같다.

 

 

또다시 구글링을 하다보니 next.js에서 lottie가 앱 성능을 저하시킨다는 stackoverflow 글을 찾을 수 있었다.

컴포넌트가 마운트될 때 lottie 라이브러리 import하고, 컴포넌트가 언마운트될 때 lottie를 destory해주는 방법으로 문제를 해결하는 방법이었다.

 

lottie files reducing performance on NextJS app

I am using lottie JSON files on my NextJS project to show some of these cool animations. The problem is the lottie JSON files are huge and really decrease the performance of the app. Has anyone fou...

stackoverflow.com

 

 

위의 글을 참고하여 lottie-web 라이브러리와 lottie json파일을 비동기적으로 호출하기 위해 lottie 컴포넌트들을 수정해주었다.

 

-  lottie json파일들을 pubilc 경로로 옮기고, lottie.loadAnimation 시 animationData가 아니라 path를 사용

-  lottie-web을 한번에 import하지 않고 Lottie useEffect내에서 비동기 처리

-  useEffect의 cleanup 함수를 활용해 lottie를 비워주기 (useEffect 내의 return에 대해서는 벨로퍼트와 함께하는 모던 리액트를 참고)

 

// 수정 전

import lottie from "lottie-web";
import ChartAnimation from "@src/assets/lotties/chart_animation.json";
import { useEffect, useRef } from "react";

const ChartAnim = () => {
  const chartRef = useRef<any>();

  useEffect(() => {
    const chart = lottie.loadAnimation({
      container: chartRef.current,
      renderer: "svg",
      loop: true,
      autoplay: true,
      animationData: ChartAnimation,
    });

    return () => {
      lottie.destroy();
    };
  }, []);

  return <div ref={chartRef}></div>;
};
// 수정 후

import { LottiePlayer } from "lottie-web";
import { useEffect, useRef, useState } from "react";

const ChartAnim = () => {
  const chartRef = useRef<any>();
  const [lottie, setLottie] = useState<LottiePlayer | null>(null);

  useEffect(() => {
    import("lottie-web").then(Lottie => setLottie(Lottie.default));
  }, []);

  useEffect(() => {
    if (lottie && chartRef.current) {
      const chart = lottie.loadAnimation({
        container: chartRef.current,
        renderer: "svg",
        loop: true,
        autoplay: true,
        path: "/static/lottie/chart_animation.json",
      });
    }

    return () => {
      lottie && lottie.destroy();
    };
  }, [lottie]);

  return <div ref={chartRef}></div>;
};

export default ChartAnim;

 

 

 

모든 lottie 컴포넌트들을 이와같이 작업해주니 페이지를 계속 옮겨다녀도 브라우저가 멈추는 현상이 해결되었다! 😹

 

 

 

 

 

 

 

🚩 마무리

 

결과적으로 적용한 방법들을 정리해보자면,

 

 

1) SVG가 정상적으로 보이게 하기 위해

 

-  next.config.js 파일에서 `swcMinify: false` 추가  →  next.js 13.0.3 버전에서 swcMinify 비활성화

-  next.config.js 파일에서 `svgo: false` 추가  →  SVGR에서 SVGO를 이용하는 svg최적화 막기위해

module.exports = {
  webpack: config => {
    config.module.rules.push({
      test: /\.svg$/,
      use: [{ loader: "@svgr/webpack", options: { svgo: false } }],
    });
    return config;
  },
  images: {
    domains: ["imagedelivery.net"],
  },
  swcMinify: false,
};

 

 

 

2) lottie로 인한 next.js 앱 성능저하를 막기 위해 

 

-  lottie 라이브러리 및 lottie json 파일 비동기 처리 

-  useEffect를 통해 컴포넌트 언마운트 시 lottie cleanup

 

 

 

lottie도, svg도, canvas도, next도 이전에 다뤄본 적이 없던 것들이라 프로젝트를 진행하면서

이런저런 이슈들을 해결하는데 생각보다 시간이 오래 걸렸다.

 

 

지금은 lottie 애니메이션마다 모두 따로따로 컴포넌트를 작성하였는데 막상 코드를 보면 lottie json파일만 다를 뿐

같은 로직을 사용하는 lottie 컴포넌트들이 많다.

 

리팩토링을 진행한다면, 이 lottie 컴포넌트들을 공통으로 뺄 수 있는 부분은 빼고 좀 더 담백한 코드로 만드는 것을 목표로 해야겠다.

 

반응형
프로필사진
개발자 삐롱히

프론트엔드 개발자 삐롱히의 개발 & 공부 기록 블로그