Skip to content

Refactor(client): bundle size optimization#199

Open
constantly-dev wants to merge 5 commits intodevelopfrom
refactor/#198/bundle-size-optimization
Open

Refactor(client): bundle size optimization#199
constantly-dev wants to merge 5 commits intodevelopfrom
refactor/#198/bundle-size-optimization

Conversation

@constantly-dev
Copy link
Member

@constantly-dev constantly-dev commented Nov 12, 2025

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

번들 사이즈 최적화 진행

⭐ PR Point (To Reviewer)

https://peppered-parade-9ba.notion.site/2a9081ae8cf980698826d0264b44eb32?source=copy_link

노션으로 대체하겠습니다!

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 페이지 로딩 중 로딩 표시 추가
  • 최적화

    • 페이지 컴포넌트 동적 로드 적용으로 초기 로딩 성능 개선
    • 번들 최적화 및 수동 청크 분할 구성 추가
  • Chores

    • 빌드 분석 도구 의존성 추가

@vercel
Copy link

vercel bot commented Nov 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
pinback-client-client Ready Ready Preview Comment Nov 12, 2025 3:05pm
pinback-client-landing Ready Ready Preview Comment Nov 12, 2025 3:05pm

@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2025

Walkthrough

이 PR은 코드 스플리팅과 동적 임포트를 통해 번들 최적화를 구현합니다. React.lazy를 사용하여 페이지 컴포넌트를 지연 로딩하고, Suspense로 로딩 상태를 처리하며, Vite 설정에서 번들 분석 및 수동 청크 생성을 추가합니다.

Changes

Cohort / File(s) 변경 사항
Suspense 및 동적 로딩
apps/client/src/layout/Layout.tsx
임포트 포맷팅 조정, Suspense 임포트 추가, <Outlet /><Suspense fallback={<div>Loading...</div>}>로 래핑하여 로딩 폴백 활성화
지연 로딩 라우트 구성
apps/client/src/routes/router.tsx
React.lazy를 사용하여 MyBookmark, Category, Level, OnBoarding 페이지 컴포넌트를 동적 임포트로 변경; Remind 라우트를 인덱스 라우트로 수정
번들 분석 및 청크 구성
apps/client/vite.config.ts
rollup-plugin-visualizer 임포트 및 플러그인 추가; 번들 분석 HTML 생성 활성화; React 및 framer-motion 라이브러리를 위한 수동 청크(@react-vendor, @framer-motion-vendor) 구성
의존성 추가
package.json
rollup-plugin-visualizer (^6.0.5) 개발 의존성 추가

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser
    participant MainBundle
    participant LazyChunk as Lazy<br/>Chunk
    participant SuspenseFallback

    User->>Browser: 애플리케이션 접속
    Browser->>MainBundle: 메인 번들 로드
    MainBundle->>Browser: 초기 UI 렌더링 (Layout + Outlet)
    
    Note over Browser,Outlet: Outlet 컴포넌트 마운트
    
    User->>Browser: 페이지 네비게이션 (e.g., MyBookmark)
    Browser->>SuspenseFallback: Suspense 폴백 표시<br/>(Loading...)
    
    par 백그라운드 청크 로드
        Browser->>LazyChunk: 지연 로딩 청크 요청
        LazyChunk->>Browser: 청크 로드 완료
    end
    
    Browser->>Browser: 컴포넌트 마운트
    SuspenseFallback->>User: 실제 페이지 콘텐츠 표시
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • 변경사항이 일관된 패턴(코드 스플리팅과 청크 구성)을 따르며 반복적입니다
  • 새로운 로직 밀도가 낮고 각 파일의 변경이 명확합니다
  • Vite 설정의 청크 구성이 의도대로 동작하는지 확인 필요

추가 검토 항목:

  • apps/client/src/routes/router.tsx의 Remind 라우트 변경이 라우팅 동작에 미치는 영향 확인
  • Suspense 폴백 UI ("Loading...")의 사용성 및 스타일링 적절성 검증

Possibly related PRs

Suggested labels

setting, feat

Suggested reviewers

  • jllee000

Poem

🐰 번들을 쪼개고, 청크를 나누고,
지연 로딩으로 속도를 높이고,
Suspense로 기다림을 다루니,
번들 크기는 작아지고,
사용자 경험은 빨라진다! ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Changes implement bundle size optimization via lazy loading and code-splitting aligned with issue #198, but include unrelated components unrelated to #25 progress bar requirements. Remove changes unrelated to the bundle optimization objective, or clarify if components are necessary for the optimization strategy.
Out of Scope Changes check ⚠️ Warning The PR includes Layout.tsx Suspense implementation, lazy loading, and bundle chunking focused on #198, but #25 progress bar requirements are not addressed. Either address #25 progress bar implementation requirements (Progress component, variants, accessibility, tests) or unlink #25 from this PR.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly describes the main change: bundle size optimization through code-splitting and lazy loading implementation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed PR 설명이 필수 섹션을 포함하고 있으며, 관련 이슈(#198)가 명시되어 있고 작업 내용(번들 사이즈 최적화)이 기술되어 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the refactor 코드 리팩토링 label Nov 12, 2025
@github-actions
Copy link

✅ Storybook chromatic 배포 확인:
🐿️ storybook

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
apps/client/vite.config.ts (2)

7-7: visualizer 자동 열기 동작을 환경에 따라 조건부로 설정하는 것을 고려하세요.

open: true 설정은 매 빌드마다 브라우저를 자동으로 열어 개발 중에 번거로울 수 있습니다.

다음과 같이 환경 변수를 통해 조건부로 설정하는 것을 권장합니다:

-    visualizer({ filename: 'dist/bundle-analysis.html', open: true }),
+    visualizer({ 
+      filename: 'dist/bundle-analysis.html', 
+      open: process.env.ANALYZE === 'true' 
+    }),

그런 다음 package.json에 별도의 스크립트를 추가할 수 있습니다:

"scripts": {
  "build:analyze": "ANALYZE=true turbo run build"
}

Also applies to: 21-21


23-40: manualChunks의 경로 매칭 로직을 더 견고하게 개선할 수 있습니다.

현재 구현은 작동하지만, 문자열 포함 검사는 오탐 가능성이 있습니다.

더 정확한 패키지 매칭을 위해 다음과 같이 개선할 수 있습니다:

         manualChunks: (id: string) => {
-          if (
-            id.includes('node_modules/react/') ||
-            id.includes('node_modules/react-dom/') ||
-            id.includes('node_modules/react-router-dom/')
-          ) {
+          if (id.includes('node_modules')) {
+            if (/[\\/]node_modules[\\/](react|react-dom|react-router-dom)[\\/]/.test(id)) {
-            return '@react-vendor';
+              return '@react-vendor';
+            }
+            if (/[\\/]node_modules[\\/]framer-motion[\\/]/.test(id)) {
+              return '@framer-motion-vendor';
+            }
           }
-          if (id.includes('node_modules/framer-motion/')) {
-            return '@framer-motion-vendor';
-          }
         },

이렇게 하면 경로 구분자를 정확히 매칭하여 오탐을 방지할 수 있습니다.

apps/client/src/layout/Layout.tsx (1)

3-3: Suspense fallback UI를 개선하는 것을 고려하세요.

Suspense 래퍼 구현은 올바르며 lazy-loaded 라우트와 잘 통합됩니다. 다만 현재 fallback이 너무 단순하여 프로덕션 환경에서는 UX 개선이 필요합니다.

더 나은 사용자 경험을 위해 적절한 로딩 컴포넌트를 사용하는 것을 권장합니다:

+import LoadingSpinner from '@components/LoadingSpinner'; // 또는 적절한 로딩 컴포넌트

 const Layout = () => {
   const location = useLocation();
   const isOnboarding = location.pathname.startsWith('/onboarding');

   return (
     <>
       <div className="flex h-screen">
         {!isOnboarding && <Sidebar />}
         <main className="bg-gray-bg flex-1 overflow-y-auto">
-          <Suspense fallback={<div>Loading...</div>}>
+          <Suspense fallback={
+            <div className="flex h-full items-center justify-center">
+              <LoadingSpinner />
+            </div>
+          }>
             <Outlet />
           </Suspense>
         </main>
       </div>
     </>
   );
 };

또는 디자인 시스템에 이미 로딩 컴포넌트가 있다면 그것을 활용할 수 있습니다.

Also applies to: 14-16

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 716a9d5 and a41e651.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • apps/client/src/layout/Layout.tsx (2 hunks)
  • apps/client/src/routes/router.tsx (1 hunks)
  • apps/client/vite.config.ts (2 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.065Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 5
File: apps/extension/src/index.css:1-1
Timestamp: 2025-08-19T17:18:57.678Z
Learning: constantly-dev는 디자인 시스템 설정 PR 머지 후 `import 'pinback/tailwind-config/shared-styles.css';`를 `app.css`나 `index.css`에서 사용하여 공유 스타일을 관리할 계획입니다.
🧬 Code graph analysis (2)
apps/client/src/routes/router.tsx (1)
apps/client/src/pages/level/Level.tsx (1)
  • Level (12-73)
apps/client/src/layout/Layout.tsx (1)
apps/client/src/shared/components/sidebar/Sidebar.tsx (1)
  • Sidebar (24-236)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: storybook
🔇 Additional comments (3)
package.json (1)

29-29: LGTM!

번들 분석을 위한 visualizer 플러그인 추가가 적절합니다. devDependencies에 올바르게 배치되었습니다.

apps/client/src/routes/router.tsx (2)

5-10: LGTM!

React.lazy를 사용한 코드 스플리팅 구현이 올바르게 되어 있습니다. 번들 최적화에 효과적입니다.


1-1: Remind 컴포넌트의 eager 로딩이 의도적인지 확인하세요.

다른 페이지는 모두 lazy 로딩을 사용하는 반면, Remind는 eager 로딩을 사용하고 있습니다. 이는 랜딩 페이지로서 즉시 로드되어야 하므로 합리적일 수 있지만, 번들 최적화 목표와 일관성을 위해 의도적인 선택인지 확인이 필요합니다.

만약 Remind도 lazy 로딩하려면 다음과 같이 수정할 수 있습니다:

-import Remind from '@pages/remind/Remind';
 import { ROUTES_CONFIG } from '@routes/routesConfig';
 import { createBrowserRouter } from 'react-router-dom';
 import Layout from 'src/layout/Layout';
 import { lazy } from 'react';

+const Remind = lazy(() => import('@pages/remind/Remind'));
 const MyBookmark = lazy(() => import('@pages/myBookmark/MyBookmark'));
 const Category = lazy(() => import('@pages/category/Category'));
 const Level = lazy(() => import('@pages/level/Level'));
 const OnBoarding = lazy(() => import('@pages/onBoarding/OnBoarding'));

참고: index: true로의 변경은 React Router v7의 올바른 패턴입니다.

Also applies to: 18-19

Comment on lines +27 to +32
if (
id.includes('node_modules/react/') ||
id.includes('node_modules/react-dom/') ||
id.includes('node_modules/react-router-dom/')
) {
return '@react-vendor';
Copy link
Collaborator

Choose a reason for hiding this comment

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

옹 이런식으로, 무거운 청크들을 분리하고 최적화하는군녀~! 굿굿

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] 번들 사이즈 최적화

2 participants