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

[개인 미션 - 성능 오답노트] 도담(김민재) 미션 제출합니다. #99

Merged
merged 12 commits into from Sep 11, 2023

Conversation

D0Dam
Copy link

@D0Dam D0Dam commented Sep 7, 2023

🔥 결과

스크린샷 2023-09-04 오후 3 35 04
  • 개선 후 (CloudFront)
스크린샷 2023-09-05 오후 12 23 52 스크린샷 2023-09-07 오후 12 53 39

✅ 개선 작업 목록

1 요청 크기 줄이기

  • 소스코드 크기 줄이기
    • 소스코드의 크기를 줄이고 최적화 하기 위해 아래와 같은 패키지를 설치해 사용했습니다.
    • css-minimizer-webpack-plugin
    • mini-css-extract-plugin
// 아래와 같이 webpack설정 파일에 추가해 주었습니다.
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }, ... ]

  optimization: {
    minimizer: ['...', new CssMinimizerPlugin()]
  }
  • 코드 스플리팅을 적용했습니다.
// 아래와 같이 webpack설정 파일을 수정해 주었습니다.
  output: {
    filename: 'bundle.[chunkhash].js',
    path: path.join(__dirname, '/dist'),
    clean: true
  },

...

  optimization: {
    splitChunks: { chunks: 'all' },
  }
  • 이미지 크기 줄이기
    • gif -> mp4, png -> webp 형식으로 변경하였습니다.

2 필요한 것만 요청하기

  • 페이지별 리소스 분리
  • 아이콘 패키지 Tree Shaking
    • 이 부분은 찾아보니 prod 에서는 웹팩이 자동적으로 걸러서 다운을 받아주더라구요!
    • 제가 잘못알고 있다면 지적부탁드립니다..!

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

  • CloudFront 캐시 설정
    • 기본 설정을 사용하였습니다.
  • GIPHY의 trending API를 Search 페이지에 들어올 때마다 새로 요청하지 않아야 한다.
    • 캐싱을 담당할 변수를 두고 코드를 일부 수정하였습니다.
// 캐싱을 담당할 변수 선언 및 export

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

export let gifCache: GifImageModel[] = [];


// 훅에서 다음과 같이 캐시가 존재하는지에따른 분기처리를 하였습니다.

  useEffect(() => {
    const fetch = async () => {
      if (status === SEARCH_STATUS.BEFORE_SEARCH) {
        if (gifCache.length === 0) {
          const gifs: GifImageModel[] = await gifAPIService.getTrending();

          gifCache.push(...gifs);
          setGifList(gifs);
        }
        if (gifCache.length !== 0) {
          setGifList(gifCache);
        }
      }
    };

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

  • 검색 결과 > 추가 로드시 추가된 목록만 새로 렌더되어야 한다.
    • gifItem에 React.memo를 적용하였습니다.
  • Layout Shift 없이 애니메이션이 일어나야 한다.
    • reflow가 일어나는 css값 top, left, right, bottom을 transform으로 변경되도록 수정했습니다. (176e675)
  • Frame Drop이 일어나지 않아야 한다.
    • (Chrome DevTools 기준) Partially Presented Frame 역시 최소로 발생해야 한다.
    • 이 부분에 대해서는... 원래 Frame Drop이 일어나지 않았고, 제 환경에서는 Partially Presented Frame 조차 찾기가 힘드네요..!
    • 3G fast, cpu 6x 에서 performance를 체크하였습니다!

🧐 공유

공유...는 아니지만 이번 테코톡에서 성능 부분을 맡았던 황펭이 리뷰어라 너무나 기쁩니다! 저번 페어도 했었어서 짱짱 친하지만 리뷰에서는 존대를 하도록 하겠습니다~!
꼭 지금 방법이 아니더라도, 제 코드에 적용되지 않은 황펭이 알고있는 다른 방법이 있다면 많이 소개시켜주면 좋을 것 같아요!
(좀 많다면... 키워드라도..!!)

너무나 보잘것 없는 제 코드... 잘 부탁드려요..!
잘 부탁드려요 황펭~!!!

@D0Dam D0Dam self-assigned this Sep 7, 2023
Copy link

@Leejin-Yang Leejin-Yang left a comment

Choose a reason for hiding this comment

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

도담 반가워요 👋

미션 수행하느라 고생했습니다 😊 매우 잘 진행한거 같아서 제가 배운 부분도 있네요.
도담 코드를 보면서 궁금한 점과 이야기해보고 싶은 점에 대해 코멘트 달았어요. 이 부분 확인해주세요!

Cloudfront 캐시 설정

이번 미션에서 CDN을 사용해 볼 수 있었는데요. 금요일 수업 내용처럼 리소스 별로 브라우저, CDN에 캐시 정책을 어떻게 가져갈 수 있을까 고민해보면 더 좋을것 같아요!

아이콘 패키지 Tree Shaking

넵 도담 말씀처럼 production 모드에서 webpack이 여러 처리를 해주고 있어요! webpack 버전이 오르면서 바뀐 점들이 많은데요. webpack이 진화해오면서 내부적으로 어떤 플러그인을 쓰고 있는지 찾아보면 좋을 것 같아요

크게 수정할 부분은 없지만 Request Changes로 리뷰 남길게요.
수고했어요 도담 😊

Comment on lines +11 to +12
rel="preload"
as="style"

Choose a reason for hiding this comment

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

폰트에 preload 속성을 사용했네요! 하나 배워갑니다 😊

Comment on lines +67 to +70
"@babel/preset-react",
{
"modules": false
}

Choose a reason for hiding this comment

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

오 modules: false 속성을 주면 어떤 효과가 있나요??

Copy link
Author

Choose a reason for hiding this comment

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

"@babel/preset-env" 프리셋에 속하는 설정입니다~!
"modules": false 를 하게 되면 Babel이 모듈 코드 변환을 하지 않습니다..!
번들러(bundler)를 사용하는 프로젝트에서 번들러는 프로젝트의 모든 모듈을 하나의 번들로 묶어주기 때문에 모듈 코드 변환이 필요하지 않습니다! 그래서 이 역할을 babel 에서 위임해준 역할이라고 보면 좋을 것 같습니다!

Comment on lines +76 to +78
"sideEffects": [
"*.css"
]

Choose a reason for hiding this comment

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

sideEffects를 추가했을 때 체감되는 효과도 궁금하네용

Copy link
Author

Choose a reason for hiding this comment

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

글쎄요... 체감..? 까지는 모르겠지만 굳이 불필요한 작업을 막을 수 있다는 면에서 한 번 사용해 보면 좋다고 생각했습니다!

src/App.tsx Outdated
Comment on lines 4 to 5
const Search = lazy(() => import('./pages/Search/Search'));
const Home = lazy(() => import('./pages/Home/Home'));

Choose a reason for hiding this comment

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

Suggested change
const Search = lazy(() => import('./pages/Search/Search'));
const Home = lazy(() => import('./pages/Home/Home'));
const Home = lazy(() => import(/* webpackChunkName: "home" */ './pages/Home/Home'));
const Search = lazy(() => import(/* webpackChunkName: "search" */ './pages/Search/Search'));

이런식으로 주석을 추가하면 webpack 번들링 과정에서 나온 청크파일에 작성한 이름을 부여한다고 하네요. 대신 사용하려면 tsconfig 파일에서 컴파일 과정 중 주석 삭제를 하지 않도록 해야합니다!

Copy link
Author

Choose a reason for hiding this comment

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

오! 배워갑니다👍

Comment on lines 22 to 25
<picture>
<source type="image/webp" className={styles.heroImage} />
<img className={styles.heroImage} src={heroImage} alt="hero" />
</picture>

Choose a reason for hiding this comment

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

Suggested change
<picture>
<source type="image/webp" className={styles.heroImage} />
<img className={styles.heroImage} src={heroImage} alt="hero" />
</picture>
<img className={styles.heroImage} src={heroImage} alt="hero" />

webp 이미지만 사용한다면 picture 태그를 사용하지 않아도 될 거 같네요. picture 태그는 webp를 지원하지 않는 환경에 다른 이미지 포맷을 보여주기 위해 사용할 수 있겠네요!

Copy link
Author

Choose a reason for hiding this comment

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

헉.. 사실 다른 파일도 고려하다가 결국 한가지만 사용하게 된 걸 반영을 안했네요..🥲
수정하겠습니다~!

@@ -24,7 +24,7 @@
}

.selectedItemContainer.showSheet {
right: 0;
transform: translateX(-320px);

Choose a reason for hiding this comment

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

👍

Comment on lines +61 to +69
if (gifCache.length === 0) {
const gifs: GifImageModel[] = await gifAPIService.getTrending();

gifCache.push(...gifs);
setGifList(gifs);
}
if (gifCache.length !== 0) {
setGifList(gifCache);
}

Choose a reason for hiding this comment

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

저는 APIService에서 캐싱 작업을 처리했는데, 도담은 사용하는 곳에서 처리를 해주었네요! 저는 커스텀 훅에서는 외부에서 데이터를 받아올 뿐 어디서 받아오는지 몰라야 한다고 생각했습니다. 도담은 이 부분에 대해서 어떻게 생각하나요??

그리고 지금은 새로고침하면 캐싱된 값이 초기화되는데, 캐시를 유지하고 싶으면 어떻게 할 수 있을까요?

Copy link
Author

Choose a reason for hiding this comment

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

저는 커스텀 훅에서는 외부에서 데이터를 받아올 뿐 어디서 받아오는지 몰라야 한다고 생각했습니다.

저도 황펭의 의견에 동의합니다! 하지만 이번 미션에서 구현할 때는 내장 메서드에 의존하지 않고 어떻게 캐시를 만들면 좋을 지 고민하다보니 결국 저장을 할만한 공간이 필요하다고 판단하고 좀 특이하게(?) 짜 봤습니다..! ㅎㅎ

새로고침하면 캐싱된 값이 초기화되는데, 캐시를 유지하고 싶으면 어떻게 할 수 있을까요?

프론트 단에서는 쿠키, 웹 스토리지, 캐시 api 정도가 있을 것 같네요!

Comment on lines +32 to +34
new MiniCssExtractPlugin({
filename: '[name].css'
})

Choose a reason for hiding this comment

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

css에는 hash 값을 부여하지 않은 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

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

사실 별다른 이유는 없었습니다..! 다만 이번 미션에서 중점적으로 체크했던 파일이 js와 assets 쪽 파일이었고, 한 번 최적화 할 것을 생각해서 캐싱 관리 쪽은 신경을 안 썻던 것 같습니다.🥲

},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif|mp4|webm|webp)$/i,
loader: 'file-loader',
options: {
name: 'static/[name].[ext]'

Choose a reason for hiding this comment

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

파일도 hash 값을 부여하지 않은 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

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

css와 이유는 살짝 겹치지만, 추가적으로 파일들은 변경사항이 거의 없다고 판단했습니다!

@@ -49,6 +56,7 @@ module.exports = {
]
},
optimization: {
minimize: false
splitChunks: { chunks: 'all' },

Choose a reason for hiding this comment

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

all 옵션을 사용해서 비동기, 동기 청크를 공유했을 때 어떤 이점이 있었나요??

Copy link
Author

@D0Dam D0Dam Sep 10, 2023

Choose a reason for hiding this comment

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

비동기, 동기 청크를 공유한다는 것은 로드되는 모듈 간에 공통된 의존성을 가지게 된다는 것이라고 할 수 있습니다. 이 덕분에 중복된 코드가 줄어들고 번들 크기가 더욱 최적화 되는 효과를 얻을 수 있었습니다~!

@D0Dam
Copy link
Author

D0Dam commented Sep 10, 2023

황펭! 자세히 봐 주셔서 감사합니다! 황펭이 남겨준 피드백에 답글 달았습니다~! 수정한 내용은... 별로 없네요..🥲
캐싱 하는 로직도 황펭처럼 Cache api 를 사용해 보고 싶었는데, 제 할일 우선순위에서 밀려났습니다.. 하하..
제 프로젝트팀은 레벨 3보다 지금 더 바쁜 것 같아요.. 펀잇은 어떤가요??
아무튼! 황펭 덕분에 모르는 개념들을 알아갈 수 있어서 너무 좋았습니다! 확인 부탁드려요~!

Copy link

@Leejin-Yang Leejin-Yang left a comment

Choose a reason for hiding this comment

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

도담 답글 확인했어요! 저도 도담 코드 보면서 많이 배웠습니다 😊
저희 팀도 이제 슬슬 바빠질거 같아요 ㅎㅎ..
파이팅입니다 도담 이만 머지할게요~!

@Leejin-Yang Leejin-Yang merged commit 7fe7105 into woowacourse:d0dam Sep 11, 2023
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.

None yet

2 participants