Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[성능 베이스캠프 미션] 병민(윤병인) 미션 제출합니다. #39

Merged
merged 32 commits into from
Sep 7, 2022

Conversation

airman5573
Copy link

@airman5573 airman5573 commented Sep 4, 2022

🔥 결과

/_ 개선 목표에 있는 측정 항목들에 대해 개선 작업 전/후의 성능 측정 결과를 적어주세요. _/

sc_ 215

- 개선 후 (CloudFront)

sc_ 110

sc_ 139

✅ 개선 작업 목록

/_ 각 요구사항을 위해 어떤 개선 작업을 진행했는지 적어주세요
코드 변경사항으로 확인하기 어려운 CloudFront 설정 사항 등은 리뷰어가 확인할 수 있게 스크린샷이나 적용한 항목들을 적어주면 좋겠지요? 🙂
_/

1 요청 크기 줄이기

2 필요한 것만 요청하기

  • 페이지별 리소스 분리
  • 아이콘 패키지 Tree Shaking
    • production mode를 통해 사용하는 아이콘만 가져왔습니다

3 같은 건 매번 새로 요청하지 않기

  • CloudFront 캐시 설정 (설정값, 해당 값을 설정한 이유 포함)
    모든 파일에 대한 캐쉬를 1년으로 설정했습니다.
    다만 이렇게 할 경우 파일을 S3에 업로드 했을때, cloudfront에서 기존에 캐싱한 파일들을 직접 무효화 해줘야 하는 불편함이 있습니다.
    index.html파일만 캐싱을 안하면 S3에 새로 파일을 올릴때마다 알아서 갱신이 되서 편하지만, LCP 1.2초를 넘기는 문제가 발생했습니다.
    아직 이유는 잘 모르겠습니다. 그래서 우선 캐쉬를 1년으로 설정하고, 새로 번들할때 직접 무효화 해주는 방식을 선택했습니다.

  • GIPHY의 trending API를 Search 페이지에 들어올 때마다 새로 요청하지 않아야 한다.

4 최소한의 변경만 일으키기

🧐 공유

/_ 작업하면서 든 생각, 질문, 새롭게 학습하거나 시도해본 내용 등등 공유할 사항이 있다면 자유롭게 적어주세요 _/

@airman5573 airman5573 assigned airman5573 and unassigned lokba Sep 4, 2022
Comment on lines +20 to +22
export default memo(GifItem, (prevProps, nextProps) => {
return prevProps.id === nextProps.id;
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 받을 수 있군요.. 얕은 비교 안하고..
꿀팁 감사합니다

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : 여기에서도 소소한 개선 포인트를 찾으셨네요~
아주 좋습니다.👍

cursorRef.current.style.left = `${mousePosition.pageX}px`;
}
}, [mousePosition]);
console.log('useEffect is called');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커서마저 최적화 해버린 그에게 남아있는 한 톨의 인간미

Copy link
Author

@airman5573 airman5573 Sep 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jin7969
Copy link

jin7969 commented Sep 5, 2022

병민만의 코드 멋지네요 ㄷㄷ;; 👏👏

Copy link

@lokba lokba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

병민 반갑습니다. 리뷰가 많이 늦었네요.
코드를 하나하나 훓어보면서 많이 생각하고 배운 것 같네요.
무엇보다 상태를 하나라도 줄여서 리렌더링을 막을려고 많이 노력하신 것 같은데 해당 부분 인상 깊었습니다.

병민과 핑퐁하고 싶은 부분이 존재해서, 코멘트를 꽤나 남겼네요.
일정이 워낙 바쁘다 보니, 모든 코멘트에 답변을 안 달아주셔도 됩니다.

이번 리뷰에서는 근로에서 배운 RCA 룰을 적용해봤어요.
이거 꽤나 리뷰어의 생각을 대략적으로 알려줘서 저는 편하더라고요.

RCA 룰

r: 꼭 반영해 주세요. 적극적으로 고려해 주세요. (Request changes)
c: 웬만하면 반영해 주세요. (Comment)
a: 그냥 사소한 의견입니다. (Approve)

반영하시고, review 다시 요청해주세요.

<link
href="https://fonts.googleapis.com/css2?family=Josefin+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"
rel="preload"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : 폰트를 preload하니, 확실히 FOUT에서 오는 불편함이 해소되기는 하네요.👍

질문 드리고 싶은게 있습니다.
프로젝트 상으로는, 두 개의 웹 폰트(normal, italic)를 로드하고 있습니다.
컨텐츠를 많이 보여주는 사이트인 경우, 페이지에서 다양한 웹 폰트를 사용할 수도 있다고 생각하는데요. 이 경우 웹 폰트 로드 전략은 어떻게 가져가실 건지 궁금합니다.

만약 모든 폰트를 preload하지 않는다고 한다면, preload하지 않은 폰트가 적용된 텍스트는 어떤식으로 UX를 개선할지 궁금합니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 사실 가능하면 폰트를 적게 사용하는게 가장 좋긴 합니다
  2. 한글폰트인 경우에는 공원의 강의때 처럼, 같은 폰트는 한글 폰트에서 제외할것 같아요
  3. 다만, textarea나 input이 있는 경우에는 간호사라는 말을 입력할때 을 한번 거치는데 이때 이 글자가 안보일것이기 때문에 이런 경우에는 그냥 한글 폰트 최적화 안하고 그냥 사용할것 같아요
  4. 물어보신 다양한 웹 폰트를 사용하는 경우에는 어쩔수 없이 모든 폰트를 로드할것 같아요.
  5. preload하지 않은 폰트가 적용된 텍스트가 있다면, "기존 폰트를 보여주고 로드가 되면 새로운 폰트로 갈아끼우기" 라는 전략이 있는걸로 알고 있는데, 저는 갑자기 뺙 하고 폰트가 변하는것이 사용자에게 더 안좋은 경험을 끼칠 수 있다고 생각해요. 그래서! 폰트가 로드되기 전에는 안보여주고 다 로드가 되면 그때 폰트가 나오도록 할것 같습니다 :D

혹시 록바가 생각하는 좋은 아이디어가 있나요?

Copy link

@lokba lokba Sep 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

폰트를 preload하니, 확실히 FOUT에서 오는 불편함이 해소되기는 하네요.👍

지금 다시보니 잘못 작성했네요~ FOUT(flash of unstyled text) -> FOIT(flash of invisible text) 였네요.

상황별로 자세하게 적어주셔서 감사합니다.
갑자기 뺙 하고 폰트가 변하는것이 사용자에게 더 안좋은 경험을 끼칠 수 있다고 생각해요.
저도 공감합니다. 폰트 관련해서 기술 블로그를 보다가 좋은 라이브러리가 존재하더라고요.
Font Face Observer라는 라이브러리인데, 해당 라이브러리를 사용하면 웹 폰트가 로드가 완료되는 시점을 파악할 수 있어요.

const font = new FontFaceObserver('Josefin Sans');
const headRef = useRef<HTMLHeadingElement>(null);

useEffect(() => {
   font.load().then(function () {
      // 폰트가 로드 완료되는 시점
      headRef.current?.classList.add('font-loaded');
    });
}, []);

return (
   <h1 ref={titleRef}>memegle</h1>
);

폰트가 로드가 완료되었을 경우, 해당 DOM 요소에 class를 주고
font-loaded가 되었을 때 스무스하게 폰트가 적용되는 transition을 적용하면 갑자기 뺙 하고 폰트가 변하지는 않을 것 같네요.

관련 블로그

href="static/josefin-sans-400-700-normal.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : 하나 배워갑니다.

스크린샷 2022-09-07 오전 1 49 26

정말 crossorigin 속성을 제거하니, 브라우저에서 2번 폰트를 요청하게 되네요. 폰트 하나를 적용하는데도 신경 많이 쓴것이 코드에서 보이네요.

관련 포스트

index.html Outdated
font-weight: 400 700;
font-display: swap;
src: url(static/josefin-sans-400-700-normal.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : unicode range...까지 적용하셨네요.😎
제 생각에는 유의미한 효과는 못봤을 것 같은데, 적용한 이유가 궁금합니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 설정한것은 아니고 구글에서 설정한것을 그대로 복붙한겁니다 ㅎㅎ
그런데 생각해보니 저는 어차피 preload를 했기 때문에 폰트를 쓰던 안쓰던 불러는 올것 같네요!
지워도 될것 같습니다 :D

sc_ 303

https://stackoverflow.com/a/65424718/9279003

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다 :D
569dd4d

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다~

index.html Outdated
crossorigin="anonymous"
/>
<style>
/* font */
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r : 불필요한 주석이라고 생각합니다. @font-face로 충분히 작성자에게 정보를 제공한다고 생각합니다. 어떻게 생각하시나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동의합니다! 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다 :D

1167829

src/App.tsx Outdated
<Route
path="/"
element={
<React.Suspense fallback={<>loading...</>}>
Copy link

@lokba lokba Sep 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c : Suspense를 페이지 컴포넌트 바로 상단에 배치하셨군요.

아래 영상을 한번 보실까요?
2022-09-07-21024

동적으로 Home 컴포넌트를 받아오고 렌더링하는 순간을 자세하게 보시죠.
Footer 컴포넌트에서 layout shift 현상이 일어나는 것을 볼 수 있습니다.
실제로 lighthouse를 돌렸을 때, CLS 점수가 아쉽기도 하고요.
어떻게 생각하실지 궁금합니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 맞네요,,,흠흠,,, !!
Footer를 바닥에 붙여볼까요?
위쪽의 Navigation은 두는게 사용자 경험에 더 좋을것 같아서요.

어떻게 생각하시나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

우선 Footer까지 Suspense에 넣었습니다 :D

60cffe5

Copy link

@lokba lokba Sep 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아주 좋네요~ 반영된 결과로 메인 페이지 대상으로 Lighthouse 검색결과 CLS 지표가 많이 좋아졌네요.
스크린샷 2022-09-07 오후 8 11 46

</section>
);
};
const SearchBar = React.forwardRef(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : 비제어 컴포넌트로 바꾸면서 자연스레 forwardRef까지...좋네요💯

/>
<SearchResult status={status} gifList={gifList} loadMore={loadMore} />
<SearchBar onEnter={handleEnter} onSearch={handleSearch} ref={inputRef} />
<SearchResult status={status} gifList={gifList} onLoadMore={handleLoadMore} />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : loadMore -> onLoadMore 세심하시네요. 💯

private staledTime = 0; // 1 day
private cacheTime = 0;

constructor(data: T | UnInitialized, staledTime = 86400) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : 제 개인적인 의견인데, 처음 봤을 때 살짝 헷갈렸어요.
status에도 uninitialized가 있어서 UnInitializedData로 타입명을 지으면 어떨까라는 생각도 들긴 하네요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

분명한 네이밍 좋습니다 :D

9ca8935

| { status: 'staled'; data: T }
| { status: 'fresh'; data: T };

class MemoryCache<T> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : MemoryCache 인상깊게 코드 잘봤습니다.
코드도 굉장히 명시적이고 가독성 좋게 잘 짜신 것 같아요~

path: path.join(__dirname, '/dist'),
filename: '[name]-[chunkhash].js',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : contenthash가 아닌 chunkhash를 사용한 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트를 해보니, chunkhash를 쓰면 js파일을 변경했음에도 css파일의 파일명이 바뀌었고,
contenthash를 쓰면 js파일을 변경했을때 js파일만 파일명이 바뀌었네요(css 파일명은 그대로).
CSS파일의 캐쉬를 생각하면 contenthash로 통일하는게 더 좋을것 같네요 :D

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다 :D

d91ca57

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트까지 해주셔서 감사합니다. 저도 웹팩 설정할때 찾아봤는데, contenthash와 chunkhash의 차이점이 존재하더라고요.

Copy link

@lokba lokba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

병민 수정사항 잘 봤습니다~ 👍👍👍
질문해주신 부분에 답장 드렸고, 추가적으로 피드백 하나만 남겼습니다.
꼭 반영할 필요없으시고, 혹시나 request changes로 남기겠습니다.
확인하시고 다시 리뷰요청주세욥!!

import { GifImageModel } from '../../../../models/image/gifImage';

import styles from './GifItem.module.css';

type GifItemProps = Omit<GifImageModel, 'id'>;
type GifItemProps = GifImageModel;

const GifItem = ({ imageUrl = '', title = '' }: GifItemProps) => {
Copy link

@lokba lokba Sep 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a : 해당 부분은 반영할 필요는 없습니다.
이미 인지하고 있을 수도 있지만, 많은 부분에서 성능 개선을 해주셔서 추가적으로 개선할 포인트 하나를 제시하고만 갑니다.

lighthouse 로딩 성능 스크린샷
스크린샷 2022-09-07 오후 8 12 59

현재 gif로 로드되는 리소스를 webm이나 mp4 포맷으로 변환하면 많은 리소스를 아낄 수 있을 것으로 보이네요.
관련 문서에 따르면, webm이 mp4보다 압축률이 좋아서 용량이 더 작다고 하네요.

관련 문서

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 맞습니다 !
저도 고민을 했는데, 아무래도 gif 검색 사이트라는 점을 고려해봤을때
사용자가 메인(홈)페이지에서 다운받은 파일(우클릭 -> save)은 mp4이고 검색 페이지에서 다운받는 파일은 gif라면
조금 혼동이 오지 않을까 싶어, 성능을 조금 내려놓고 컨셉을 지키는 방향을 선택했습니다.

혹시 록바는 이 부분에 대해서 어떻게 생각하시나요? 궁금합니다 :D

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

성능을 조금 내려놓고 컨셉을 지키는 방향을 선택했습니다.

오호 그러네요. 병민처럼 생각할 수 있겠군요. 저는 미션의 취지가 성능 개선이기에, gif를 모조리 video 요소로 전부 바꾸긴 했습니다.
만약...제가 실제 memegle의 개발자라면, 병민과 같은 생각을 할 것 같네요. 의견 상세히 적어주셔서 감사합니다. :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

미션의 취지도 맞는 말이네요 👍
생각 공유 감사합니다 :D

Copy link

@lokba lokba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

병민 수고하셨습니다.
리뷰가 늦어서 Approve도 딜레이되어서 죄송하네요.

코드에서 고민의 흔적이 많이 느껴져서 좋았습니다.
CustomCursor, AnimatedPath와 같이 제가 생각하지 못한 부분에서 렌더링 성능을 개선하셨는데 많이 배웠습니다.
단순한 의견의 피드백이었지만, 바로 적용해주셔서 좋았습니다.

이만 Approve 진행하겠습니다. 앞으로의 미션을 응원하겠습니다. 필승!

@lokba lokba merged commit 2cf6da4 into woowacourse:airman5573 Sep 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants