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

Bundle 사이즈 최적화 #716

Merged
merged 16 commits into from
Oct 4, 2024
Merged

Conversation

vi-wolhwa
Copy link
Contributor

@vi-wolhwa vi-wolhwa commented Sep 26, 2024

⚡️ 관련 이슈

📍주요 변경 사항

번들 사이즈 최적화 진행

Code Splitting

방법

  • router 파일의 페이지 컴포넌트를 Suspense, Lazy를 사용하여 CodeSplitting 구현
  • 각 번들 파일에 대해 개별적 chunks로 분리 (content hash)

문제

  • TreeShaking이 동작하지 않고 여전히 모든 컴포넌트를 한 번에 가져오는 문제
    • 원인 : Barrel 방식에서 Webpack은 SideEffects 가능성이 있다고 판단
    • 해결방안 : Package.json에 명시적으로 SideEffects 가능성을 배제

Code Compression

방법

  • compression-webpack-plugin을 사용하여 britli 압축


Before After
image image
image image

@vi-wolhwa vi-wolhwa added feature 기능 추가 FE 프론트엔드 labels Sep 26, 2024
@vi-wolhwa vi-wolhwa added this to the 5차 스프린트🍗 milestone Sep 26, 2024
@vi-wolhwa vi-wolhwa self-assigned this Sep 26, 2024
@vi-wolhwa vi-wolhwa changed the base branch from main to dev/fe September 26, 2024 22:43
@vi-wolhwa vi-wolhwa changed the title Refactor/715 bundle optimiziation Bundle 사이즈 최적화 Sep 26, 2024
@Jaymyong66 Jaymyong66 closed this Sep 27, 2024
@Jaymyong66 Jaymyong66 reopened this Sep 27, 2024
Copy link
Contributor

@Jaymyong66 Jaymyong66 left a comment

Choose a reason for hiding this comment

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

고생했습니다!! 번들 사이즈가 많이 줄었네요.
이야기 나누고 싶은 부분이 있어서 코멘트 남김니다~!@

Comment on lines +19 to +21
const CustomSuspense = ({ children }: { children: JSX.Element }) => (
<Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
);
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분에서 혹시 LayoutShift가 생기진 않나요?!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Layout의 모든 요소가 한 번에 렌더링 되기 때문에 Layout Shift가 생기진 않지만, (캐시가 없을 때) 로딩 후 뒤늦게 렌더링 됩니다.

헤인이 Footer이 미리 렌더링 되지 않도록 하여 Layout Shift를 해결했던 것과 동일한 이유로 Layout Shift가 발생하지 않는다고 할 수 있을 것 같습니다.

@@ -25,5 +25,6 @@ module.exports = () => {
},
],
},
devtool: 'source-map',
Copy link
Contributor

Choose a reason for hiding this comment

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

상단에 cheap-module-source-map으로 적용해놔서 지워도 되지 않을까 합니닷!
cheap으로 적용한 이유는 빠른 빌드와 실시간 리프레시가 중요하므로, 최소한의 정보를 가진 소스 맵이 더 효율적이라고 알고 있어서 입니닷.
common에 source-map을 둔 이유는 혹시나 해서 기본값으로 둔 것이었구 지워도 무방할 것 같긴합니다.

prod모드에서 hidden 소스맵을 쓴 이유는 소스 맵을 제공하지만, 클라이언트 측에서 직접 접근할 수 없도록 합니다. 즉, 소스 맵 파일이 생성되지만, 웹 페이지에서 직접 링크되지 않기 때문에 외부 사용자에게 원본 소스 코드를 노출하지 않는다고 알고 있습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

반영하였습니다!

Comment on lines +26 to +29
<CustomSuspense>
<NotFoundPage />
</CustomSuspense>
),
Copy link
Contributor

Choose a reason for hiding this comment

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

CustomSuspense를 Layout 내부 같은 곳에서 한번에 걸어도 괜찮을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

제가 지금 생각했을 땐 방법이 떠오르지는 않네용
같이 이야기 해 볼 사항인 것 같습니다.

Comment on lines +10 to +17
const LandingPage = lazy(() => import('@/pages/LandingPage/LandingPage'));
const TemplatePage = lazy(() => import('@/pages/TemplatePage/TemplatePage'));
const TemplateUploadPage = lazy(() => import('@/pages/TemplateUploadPage/TemplateUploadPage'));
const SignupPage = lazy(() => import('@/pages/SignupPage/SignupPage'));
const LoginPage = lazy(() => import('@/pages/LoginPage/LoginPage'));
const NotFoundPage = lazy(() => import('@/pages/NotFoundPage/NotFoundPage'));
const TemplateExplorePage = lazy(() => import('@/pages/TemplateExplorePage/TemplateExplorePage'));
const MyTemplatePage = lazy(() => import('@/pages/MyTemplatesPage/MyTemplatePage'));
Copy link
Contributor

Choose a reason for hiding this comment

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

혹시 lint 에러가 나지 않았나요?!
Fast refresh only works when a file only exports components. Move your component(s) to a separate file.eslint(react-refresh/only-export-components)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이 부분에 ESLint 에러가 발생하고 있습니다.

이 에러는 DX 향상 목적의 에러인데요.
소스코드 변경 시, 브라우저에서 해당 부분만 빠르게 업데이트하여 개발생산성을 높힐 수 있다는 경고입니다.

이 ESLint 에러 같은 경우에는 컴포넌트의 Default export 또는 컴포넌트를 리턴하고 있지 않아서 발생한다고 하는데, lazy 로딩을 사용할 수 없게 됩니다.

따라서 ESLint에서 이 에러를 경고처리만 하여서 개발자가 파악할 수 있도록 하여 사용하는 케이스도 있다고 합니다.

"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"lint:style": "stylelint '**/style.ts' --fix"
},
"keywords": [],
"author": "",
"sideEffects": false,
Copy link
Contributor

Choose a reason for hiding this comment

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

해당 부분을 false로 해도 괜찮나요?! API 호출이나 Global style을 주는 경우 sideEffect이지 않을까 해서 질문드립니닷

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sideEffects: false 설정 후 무결성 검사

  1. 스타일 파일이 제대로 적용되는지 확인

    • import './styles.css';와 같은 스타일 파일이나 CSS-in-JS 코드가 트리쉐이킹 과정에서 제거되지 않았는지 확인합니다.
    • Webpack 또는 Babel이 스타일 파일을 잘 유지하고 있는지 검사합니다.
  2. 폴리필 제거 여부 확인

    • 프로젝트에서 사용되는 core-jsregenerator-runtime 같은 폴리필이 트리쉐이킹 중에 제거되지 않았는지 확인합니다.
    • 특히 폴리필이 특정 브라우저 호환성을 위해 필요한 경우, 제거되지 않아야 합니다.
  3. ES 모듈로부터의 사이드 이펙트 확인

    • 일부 모듈이 import될 때 실행되는 사이드 이펙트가 있을 수 있습니다. 예를 들어, 글로벌 상태 변경, 이벤트 리스너 추가 등이 발생하는 모듈이 트리쉐이킹으로 제거되지 않는지 확인합니다.
  4. 전역 상태 변화 여부 확인

    • 전역에서 상태를 변경하는 라이브러리나 코드가 있을 경우 트리쉐이킹 중에 제거되지 않았는지 확인합니다. 예: redux, mobx와 같은 상태 관리 라이브러리.
  5. 타사 라이브러리 확인

    • 일부 타사 라이브러리는 sideEffects: false로 인해 의도치 않게 코드가 삭제될 수 있습니다. 해당 라이브러리의 문서에서 sideEffects 설정에 대한 가이드를 따르는지 확인합니다.
  6. Lazy-loaded 모듈 정상 동작 확인

    • 코드 스플리팅 및 React.lazy() 등을 사용한 lazy loading 모듈이 제거되지 않고 정상적으로 로드되는지 확인합니다.
  7. 애니메이션 및 DOM 조작 코드 확인

    • 애니메이션, 이벤트 리스너, DOM 조작과 같은 사이드 이펙트가 발생하는 코드를 사용하는 경우 트리쉐이킹 중에 제거되지 않았는지 확인합니다.
  8. 테스트 환경에서 코드 실행 확인

    • sideEffects가 제거된 코드가 의도대로 작동하는지 확인하기 위해 모든 테스트가 통과하는지 확인합니다.
    • 특히 UI, DOM, 애니메이션 관련 테스트가 잘 작동하는지 중점적으로 검사합니다.
  9. 동적 import 사용 여부 확인

    • 동적으로 import되는 모듈이 제거되지 않았는지 확인합니다. 예: import() 구문을 사용하는 경우.
  10. 프로덕션 빌드 최종 확인

    • 프로덕션 빌드를 진행한 후 전체 애플리케이션의 주요 기능을 테스트하여 부작용이 발생하지 않았는지 확인합니다.
    • 특히 중요한 기능과 유저 플로우를 꼼꼼히 체크합니다.

Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분에 대해서 저도 검색해보았는데, 이렇게 명시적으로 false 하거나 [] 배열 안에 명시적으로 안전하다고 여기는 파일을 넣어주는 방식도 있다고 하네요!!

  • 특정 파일에서 sideEffects가 발생하지 않을 것을 설정
    package.json에 "sideEffects": ["특정파일 경로"] 설정
    {
    "name": "tree-shaking",
    "version": "1.0.0",
    "sideEffects": ["./src/components/NoSideEffect.js"]
    }

Hain-tain
Hain-tain previously approved these changes Oct 2, 2024
@Hain-tain Hain-tain self-requested a review October 4, 2024 08:56
@Jaymyong66 Jaymyong66 merged commit 18dc932 into dev/fe Oct 4, 2024
3 checks passed
@Jaymyong66 Jaymyong66 deleted the refactor/715-bundle-optimiziation branch October 4, 2024 08:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FE 프론트엔드 feature 기능 추가
Projects
Status: Weekend Done
Development

Successfully merging this pull request may close these issues.

3 participants