Skip to content

Comments

Refactor(client): bundle size optimization#199

Merged
constantly-dev merged 6 commits intodevelopfrom
refactor/#198/bundle-size-optimization
Feb 18, 2026
Merged

Refactor(client): bundle size optimization#199
constantly-dev merged 6 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

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

Summary by CodeRabbit

릴리스 노트

  • 최적화

    • 번들 청킹 전략을 개선하여 애플리케이션 성능을 최적화했습니다.
  • 기타

    • 라우팅 구조를 조정했습니다.

@vercel
Copy link

vercel bot commented Nov 12, 2025

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

Project Deployment Actions Updated (UTC)
pinback-client-client Ready Ready Preview, Comment Feb 18, 2026 1:08pm
pinback-client-landing Ready Ready Preview, Comment Feb 18, 2026 1:08pm

@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2025

걷기

라우팅 설정을 변경하여 Remind 경로를 인덱스 라우트로 전환하고, Vite 빌드 설정에서 번들 시각화 플러그인과 수동 청크 분할(React 및 framer-motion 벤더 분리)을 추가했으며, 관련 dev 의존성을 package.json에 포함했습니다.

변경 사항

그룹 / 파일(들) 요약
라우팅 구성
apps/client/src/routes/router.tsx
Remind 라우트를 경로 기반 라우트에서 인덱스 라우트(index: true)로 변경하여 기본 자식 렌더링 동작 수정.
번들 최적화 설정
apps/client/vite.config.ts
rollup-plugin-visualizer 플러그인 추가(bundle-analysis.html 생성 및 자동 열기), 수동 청크 분할 구성으로 React 및 framer-motion을 별도 벤더 청크로 분리.
의존성 관리
package.json
rollup-plugin-visualizer(^6.0.5)를 devDependencies에 추가.

예상 코드 리뷰 노력

🎯 2 (간단함) | ⏱️ ~12분

추천 검토자

  • jllee000
  • jjangminii

🐰 번들을 쪼개고 나누어,
시각화로 밝혀보니,
무거운 것들 한눈에 보이네.
React와 프레이머 분리되어,
빠른 로딩의 꿈을 꿔본다! ✨📦

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 라우팅 변경(Remind 인덱스 라우트)은 번들 최적화와 직접적인 관련이 없으며, PR 목표 범위를 벗어난 변경사항으로 보입니다. router.tsx의 라우팅 변경이 번들 최적화와 어떤 관계가 있는지 명확히 하거나, 별도 PR로 분리하는 것을 권장합니다.
Linked Issues check ❓ Inconclusive 번들 사이즈 최적화 #198 요구사항(번들 최적화)은 vite.config.ts의 수동 청크 분할과 visualizer 추가로 충족되었으나, #25는 이 PR과 무관한 progress bar 구현 이슈입니다. #25는 이 PR의 범위와 무관합니다. #198의 번들 최적화만 관련 이슈인지 확인하고, #25 링크 제거를 권장합니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 '번들 사이즈 최적화'라는 주요 변경 사항을 명확하게 요약하고 있으며, 실제 변경사항(Vite 설정 및 라우팅 최적화)과 관련이 있습니다.
Description check ✅ Passed PR 설명은 템플릿 구조를 준수하고 있으며, 관련 이슈(#198), 작업 내용, 리뷰어 공지사항(Notion 링크)이 포함되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/#198/bundle-size-optimization

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

github-actions bot commented Nov 12, 2025

✅ 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.

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

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/client/src/routes/router.tsx (1)

1-12: 🛠️ Refactor suggestion | 🟠 Major

번들 최적화 목표 대비 정적 import — React.lazy() 적용 필요

PR 목표("동적 로딩으로 초기 로드 개선")를 달성하려면 라우트 컴포넌트를 React.lazy() + 동적 import()로 전환해야 합니다. vite.config.tsmanualChunks 설정은 정적으로 import된 모듈을 청크로 묶을 뿐, 라우트별 코드 스플리팅을 생성하지 않습니다. 현재 구조에서는 첫 번째 페이지 진입 시 모든 페이지 코드가 함께 번들에 포함됩니다.

♻️ 라우트별 코드 스플리팅 적용 예시
-import Category from '@pages/category/Category';
-import Level from '@pages/level/Level';
-import Login from '@pages/login/Login';
-import MyBookmark from '@pages/myBookmark/MyBookmark';
-import GoogleCallback from '@pages/onBoarding/GoogleCallback';
-import OnBoarding from '@pages/onBoarding/OnBoarding';
-import PrivacyPolicy from '@pages/policy/PrivacyPolicy';
-import TermsOfService from '@pages/policy/TermsOfService';
-import Remind from '@pages/remind/Remind';
+import { lazy } from 'react';
+
+const Category = lazy(() => import('@pages/category/Category'));
+const Level = lazy(() => import('@pages/level/Level'));
+const Login = lazy(() => import('@pages/login/Login'));
+const MyBookmark = lazy(() => import('@pages/myBookmark/MyBookmark'));
+const GoogleCallback = lazy(() => import('@pages/onBoarding/GoogleCallback'));
+const OnBoarding = lazy(() => import('@pages/onBoarding/OnBoarding'));
+const PrivacyPolicy = lazy(() => import('@pages/policy/PrivacyPolicy'));
+const TermsOfService = lazy(() => import('@pages/policy/TermsOfService'));
+const Remind = lazy(() => import('@pages/remind/Remind'));

그리고 최상위에서 Suspense로 감싸야 합니다. PR에서 추가된 로딩 인디케이터를 Layout 또는 RouterProvider 레벨의 fallback으로 활용할 수 있습니다:

 import { ROUTES_CONFIG } from '@routes/routesConfig';
-import { createBrowserRouter } from 'react-router-dom';
+import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { Suspense } from 'react';
+import LoadingIndicator from 'src/components/LoadingIndicator'; // 실제 경로로 교체

Layout 컴포넌트 내부 또는 각 라우트의 element<Suspense fallback={<LoadingIndicator />}> 로 감쌉니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/routes/router.tsx` around lines 1 - 12, The router currently
statically imports page components (Category, Level, Login, MyBookmark,
GoogleCallback, OnBoarding, PrivacyPolicy, TermsOfService, Remind) so all pages
are bundled up front; change each static import in router.tsx to lazy-loaded
components using React.lazy(() => import('...')) for each of those symbols and
update the route entries (where ROUTES_CONFIG is used) to reference the lazy
components, then ensure you wrap the router render (either in Layout or at
RouterProvider level) with React.Suspense and pass the existing LoadingIndicator
(or Layout fallback) as the fallback so route components load dynamically and
enable per-route code splitting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/client/src/routes/router.tsx`:
- Around line 1-12: The router currently statically imports page components
(Category, Level, Login, MyBookmark, GoogleCallback, OnBoarding, PrivacyPolicy,
TermsOfService, Remind) so all pages are bundled up front; change each static
import in router.tsx to lazy-loaded components using React.lazy(() =>
import('...')) for each of those symbols and update the route entries (where
ROUTES_CONFIG is used) to reference the lazy components, then ensure you wrap
the router render (either in Layout or at RouterProvider level) with
React.Suspense and pass the existing LoadingIndicator (or Layout fallback) as
the fallback so route components load dynamically and enable per-route code
splitting.

@constantly-dev constantly-dev merged commit 6b66494 into develop Feb 18, 2026
9 checks passed
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