0. Intro
기존에는 Three.js를 사용해서 외부 소스의 gltf 모델링 파일을 컴포넌트로 변환하여 웹에서 3d를 구현했었다. 하지만 이번에 꼭 사용해보고 싶은 게 있어 3d 모델링 툴인 Spline을 사용해서 구현한 3d 모델링 파일을 코드로 export 하여 포트폴리오 앱에서 받아와 사용했다.
이 과정에서 모델링 파일을 받아오는 방식이 빌드 파일 내에 저장된 걸 사용하는 게 아니라 네트워크를 사용해서 받아오게끔 되어있어, 모바일에서는 정상적인 열람이 힘들 정도의 심각한 성능 저하가 발생하였다. 구글 라이트하우스를 돌려보면 데스크탑 환경에서 해당 3d 파일을 불러오는 코드만 삭제해도 퍼포먼스 점수가 28점에서 64점이 될 정도이다.
이를 해결하려면 모델링 파일 자체를 더 적은 폴리곤을 사용하거나 인터렉션을 준 부분들을 제거하는 등 개발자의 분야보다 모델러의 업무로 해결이 가능한 부분으로 보여, 현재 내 앱의 정체성과도 같은 부분이라 제거하기도 망설여지고, 그렇다고 모델링을 깎기에는 내가 알고있는 수준으로는 불가능하고, Three.js로 비슷한 인터렉션을 주는 코드를 구현하기 또한 프론트엔드 신입 취준을 위한 공부를 위주로 한 내 수준에선 아직 배우지 못한 부분이라 이러지도, 저러지도 못하고 있었다.
그러던 차, 어차피 웹 성능 최적화는 내가 목표로 하는 회사들에서 요구하는 사항이기도 하고 스스로도 처참한 Lighthouse 점수에 심히 분개하고 앞으로도 개발 커리어 전반에 있어서 웹에서 3d를 전문적으로 사용하는 프론트엔드 개발자가 되고자 하기에 우선은 해당 3d 파일을 네트워크를 사용해서 import하는 부분을 그대로 둔 상태에서 부트캠프 과정을 수강하며 배운 모든 성능 최적화 방법을 동원해 보기로 하였다. 모바일에선 3d를 제거하던 안하던 24점에서 28점으로 4점의 차이만 나는걸 보니 분명 개선할 여지가 있어 보였다.
Spline 코드 제거 전 - 데스크탑
Spline 코드 제거 후- 데스크탑
Spline 코드 제거 전 - 모바일
Spline 코드 제거 후 - 모바일
1. 이전에 이미 시도한 것들
1.1 useMemo
// 3d 모델링 파일 불러오는 함수를 Memoize 해둠.
import React, { useMemo } from 'react';
import * as S from './Styles';
function Main() {
const MemoizeSplineObj = useMemo(() => {
return (
);
}, []);
return (
{window.screen.width > 400 && MemoizeSplineObj}
{/* ... 중략 */}
);
}
export default Main;
1.2 Lazy Loading
// App.jsx 레이지 로딩
import React, { useState, useRef, Suspense } from 'react';
import { scrollToSection } from './utils/scrollToSection';
import SectionTitle from './components/common/SectionTitle';
import GlobalStyle, { Layout } from './GlobalStyle';
// component
const Nav = React.lazy(() => import('./components/common/Nav'));
// pages
const AboutPage = React.lazy(() => import('./pages/AboutPage'));
const ContactPage = React.lazy(() => import('./pages/ContactPage'));
const MainPage = React.lazy(() => import('./pages/MainPage'));
const WorksPage = React.lazy(() => import('./pages/WorksPage'));
const TestimonialPage = React.lazy(() => import('./pages/TestimonialPage'));
const ScrollToTop = React.lazy(() => import('./components/common/ScrollToTop'));
const ToggleTheme = React.lazy(() => import('./components/common/ToggleTheme'));
const Loading = React.lazy(() => import('./components/common/Loading'));
const App = () => {
const home = useRef(null);
const about = useRef(null);
const works = useRef(null);
const testimonials = useRef(null);
const contact = useRef(null);
const [theme, setTheme] = useState(`${localStorage.theme}`);
const switchTheme = () => {
return setTheme(localStorage.theme);
};
return (
<Suspense fallback={<Loading />}>
<div className="App" id={theme}>
<GlobalStyle />
<ToggleTheme
theme={theme}
setTheme={setTheme}
switchTheme={switchTheme}
/>
<ScrollToTop />
{window.screen.width > 479 && (
<Nav
scrollToSection={scrollToSection}
home={home}
about={about}
works={works}
testimonials={testimonials}
contact={contact}
/>
)}
<Layout ref={home}>
<MainPage />
</Layout>
<Layout about ref={about} max>
<SectionTitle title="about me" />
<AboutPage
scrollToSection={scrollToSection}
testimonials={testimonials}
/>
</Layout>
<Layout ref={works} max>
<SectionTitle title="works" />
<WorksPage />
</Layout>
<Layout ref={testimonials}>
<SectionTitle title="testimonials" />
<TestimonialPage />
</Layout>
<Layout ref={contact}>
<SectionTitle title="contact" />
<ContactPage />
</Layout>
</div>
</Suspense>
);
};
export default App;
1.3 compress-create-react-app
CRA로 만들어진 리액트 프로젝트의 빌드 파일에서 html, css, js 파일들을 gzip 알고리즘으로 압축시켜주는 노드 패키지이다. 이를 통해 빌드 파일의 용량을 22.10.26 현재 기준으로 21.93MB 에서 7.19MB 파일로 줄일 수 있었다. 이 용량은 앞으로 리팩토링하면서 추가적으로 구현하는 부분들이나 제거 또는 개선하는 부분들에 의해서 달라질 예정이다.
Build compressed with gz
The build size was reduced to 37% of its initial size, 13.84 MB was removed.
8.09 MB instead of 21.93 MB
Build compressed with br
The build size was reduced to 33% of its initial size, 14.74 MB was removed.
7.19 MB instead of 21.93 MB
2. 오늘 시도한 것
2.1 미사용 노드 패키지 삭제
- @reduxjs/toolkit : 기존에 redux, react-redux, redux-thunk로만 구현했기 때문에 삭제.
- antd : 현재 구현한 부분에서 사용한 적이 없으므로 우선 삭제.
- @testing-library/jest-dom, @testing-library/react, @testing-library/user-event, web-vitals : 테스트케이스 구현하지 않았으므로 삭제
- http-proxy-middleware : 이메일 전송기능을 기존에 nodemailer로 구현 시도할때 깔아두고 삭제하지 않았음. 현재 emailjs 사용하고 있고 로컬에서도 배포환경에서도 정상작동하므로 프록시로 테스트 필요 없으므로 삭제.
결론
자잘한 개선들, 예를들어 유튜브 iframe 레이지로딩이나 구글 웹폰트 최적화 정도론 해결될 문제가 아닌 것 같다. 내 기억으론 불필요하게 재렌더링되고 있는 부분도 딱히 없는걸로 기억하고 있다..
성능 최적화 개선 방향에 대한 조언을 얻고자 인프런 멘토링을 신청해뒀다.
'개인프로젝트 > 개인 포트폴리오 웹앱' 카테고리의 다른 글
리액트 포트폴리오 사이트 제작기 5편 (0) | 2022.08.19 |
---|---|
리액트 포트폴리오 사이트 제작기 4편 (0) | 2022.08.10 |
리액트 포트폴리오 사이트 제작기 3편 (0) | 2022.08.08 |
리액트 포트폴리오 사이트 제작기 2편 (0) | 2022.08.02 |
리액트 포트폴리오 사이트 제작기 1편 (0) | 2022.07.24 |