Skip to content

Setting(project): svg sprite 설정#15

Merged
jjangminii merged 12 commits intodevelopfrom
setting/#11/svg-splite
Aug 21, 2025
Merged

Setting(project): svg sprite 설정#15
jjangminii merged 12 commits intodevelopfrom
setting/#11/svg-splite

Conversation

@jjangminii
Copy link
Collaborator

@jjangminii jjangminii commented Aug 20, 2025

📌 Related Issues

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

✅ 체크 리스트

  • PR 제목의 형식을 잘 작성했나요? e.g. Feat(client): PR 템플릿 작성
  • 빌드가 성공했나요? (pnpm build)

📄 Tasks

  • svgo 설정
    1. W,H 자동 삭제
    2. 자동 프리티어
    3. current color 자동 변경
  • svg splite 세팅

⭐ PR Point (To Reviewer)

Icons svg sprite 방식 적용

svg sprite장점은 해당 pr내용과 같아요.
다만 width,height 값이 svg파일에 들어가 있으면 ui가 깨지거나 원하는대로 조정하기가 힘들어 일일이 삭제해줘야하는 번거로움이 있어 svgr로 바꿀까하는 고민이있었습니다. 하지만 다음글에 보면 svgr도 일일이 삭제해줘야하는 번거로움은 동일해보여 svg sprite 방식으로 하기로 결정했습니다.

  1. width,height 자동 삭제
    width,height는 개발자가 삭제하거나 피그마에서 export할 때 방식 수정하는 방법이 있었어요. 피그마에서 플러그인 사용해서 설정하는 방식이 익숙하지않아 svgo를 사용해서 명령어로 이미지들의 width,height 가 자동으로 삭제되게하였습니다. 그래서 저번 방식에서 추가적으로 명령어를 한번 더 입력해줘야합니다-! 그럼 자동으로 모든 파일의 width,height 삭제 되어용.. 이정도는 괜찮죠?

  2. 자동 프리티어
    명령어 입력후 아이콘의 이름이 파일에 추가될 때 자동으로 프리티어 적용이 안되서 ctrl+s해서 정렬해줬었습니다. 이부분 또한 자동으로 같이 포맷되게 적용했습니다.

  3. current color 자동 변경
    사실 이부분은 적용하지 않았습니다. 밖에서 컬러 주입하여 사용하려 fii/stroke의 컬러를 기본컬러-> current color로 자동 변환해주는게 1번과 동일하게 svgo 최적화가 있었습니다. 다만 이렇게되면 컬러를 주입하지 않을경우 색이 다 날라가거나, 기본 디폴트 컬러를 적용해두는 방식으러 해야하는데 이 방식이 더 복잡할거같다는 생각이 들었습니다. 기본 아이콘이 아닌 캐릭터같은 파일들은 밖에서 색을 주입하기도 힘들고 아이콘이 많은편이아니라 중복되고 색만 다른 아이콘들은 번거롭지만 일일이 삭제하고 주입하는 방식으로하는게 좋을것 같다고 판단했습니다. 이 방식에 대해서 추가적의 의견도 궁금합니다-!!!

사용방법

  1. design-system/src/icons/source에 원본 svg를 넣어요.
  2. pnpm icons 을 입력해요
  3. 사용할 파일에서 Icon 컴포넌트를 import 하고 name(필수), width등의 속성을 입력해요.(width,height 디폴트값 20px)
  • 현재까지 디자인 시스템에 있는 icon들은 다 추가해뒀습니다

📷 Screenshot

Summary by CodeRabbit

  • 신기능

    • 스프라이트 기반 Icon 컴포넌트 추가 — 크기·가로/세로·회전·색상 제어, aria-hidden 기본값, 타입 안전한 아이콘 이름 지원.
    • 아이콘 이름 목록을 자동 생성해 공개 타입으로 제공.
  • 작업(Chores)

    • 아이콘 최적화·스프라이트 생성 및 관련 실행 스크립트 추가.
    • SVGO 및 스프라이트 플러그인 의존성 추가 및 디자인 시스템과 각 앱 빌드 파이프라인에 통합.

@jjangminii jjangminii linked an issue Aug 20, 2025 that may be closed by this pull request
@coderabbitai
Copy link

coderabbitai bot commented Aug 20, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

디자인 시스템에 SVG 아이콘 파이프라인을 추가했습니다: SVGO 설정 및 정리 스크립트, 아이콘 목록 자동 생성 스크립트와 생성된 타입, Vite svg-sprite 플러그인 적용(패키지·앱들), 그리고 새 React Icon 컴포넌트와 관련 의존성/스크립트 변경이 포함됩니다.

Changes

Cohort / File(s) Summary
Icon 컴포넌트 공개
packages/design-system/src/icons/components/icon.tsx, packages/design-system/src/icons/index.ts
Icon React 컴포넌트 추가 및 index.ts에 재노출. 스프라이트 <use href="#icon-{name}" /> 참조, size/width/height/rotate/color/className/ariaHidden 및 기타 SVG props 전달 지원.
아이콘 이름 자동생성
packages/design-system/src/icons/iconNames.ts, packages/design-system/src/icons/scripts/generate-icon-list.ts
src/icons/source의 SVG 파일명을 스캔해 iconNames const 튜플과 IconName 유니온 타입을 생성하는 스크립트와 생성된 파일 추가(자동 생성 주석 포함).
SVGO 설정 및 정리 스크립트
packages/design-system/svgo.config.mjs, packages/design-system/package.json
SVGO 설정 파일 추가(멀티패스, viewBox 보존, removeDimensions) 및 package.json에 icons:clean, generate:icons, icons 스크립트 추가.
Vite svg-sprite 플러그인 적용 (여러 앱)
packages/design-system/vite.config.ts, apps/client/vite.config.ts, apps/extension/vite.config.ts, apps/landing/vite.config.ts
@pivanov/vite-plugin-svg-sprite 플러그인 도입 및 각 Vite 설정의 plugins 배열에 추가(iconDirs 경로 각각 지정, symbolId: 'icon-[name]', inject: 'body-last').
의존성·설정 조정
packages/design-system/package.json, package.json, apps/client/package.json, apps/extension/package.json, apps/landing/package.json, packages/design-system/tsconfig.json
@pivanov/vite-plugin-svg-sprite, svgo 등 의존성 추가/이동, tsx devDependency 추가, tsconfigtypeRoots 추가 등 의존성 및 설정 변경.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as 개발자
  participant Scripts as pnpm 스크립트
  participant SVGO as SVGO
  participant Gen as generate-icon-list.ts
  participant Vite as Vite + svg-sprite 플러그인
  participant Browser as 앱/브라우저

  Dev->>Scripts: pnpm icons:clean
  Scripts->>SVGO: src/icons/source/*.svg 최적화 (svgo.config.mjs)
  Dev->>Scripts: pnpm generate:icons
  Scripts->>Gen: SVG 파일명 스캔 -> iconNames.ts 생성
  Dev->>Vite: pnpm dev/build
  Vite->>Vite: sprite 생성(iconDirs) 및 body-last에 주입
  Browser-->>Dev: 빌드된 앱(주입된 sprite 포함)
Loading
sequenceDiagram
  autonumber
  participant UI as UI 컴포넌트
  participant Icon as Icon 컴포넌트
  participant Sprite as Injected Sprite in DOM

  UI->>Icon: <Icon name="ic_close" size=20 color="..." />
  Icon->>Icon: width/height/class/style 계산
  Icon->>Sprite: render <svg><use href="#icon-ic_close" /></svg>
  Sprite-->>UI: 아이콘이 DOM에서 렌더링됨
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

⚙️ Setting, config, frontend, needs-review

Suggested reviewers

  • constantly-dev
  • karnelll

Poem

(•ㅅ•) 🥕
아이콘들 모아 반짝임 다듬고,
당근 쥔 토끼가 파일에 춤을 추네.
한 번의 로 빛을 이어 붙여,
빌드 끝에 조용히 본문에 숨 쉬네.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch setting/#11/svg-splite

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the setting 세팅하라 세팅 label Aug 20, 2025
@github-actions github-actions bot requested a review from jllee000 August 20, 2025 19:00
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: 4

🧹 Nitpick comments (14)
packages/design-system/tsconfig.json (1)

4-5: typeRoots 설정 불필요 – 삭제 고려

design-system 패키지 내에서는 현재 vite/client, @testing-library, storybook 등 외부 글로벌 타입 참조가 없으므로,
"typeRoots": ["node_modules/@types"] 설정을 제거해도 동작에는 문제가 없습니다.
해당 옵션은 TypeScript의 기본값과 동일한 경로를 명시하고 있어 중복이므로,
향후 외부 글로벌 타입 사용 시 누락 리스크를 줄이기 위해 삭제를 권장합니다.

• 수정 위치
– packages/design-system/tsconfig.json

제안(diff):

   "compilerOptions": {
-    "typeRoots": ["node_modules/@types"],
packages/design-system/svgo.config.mjs (1)

3-8: SVG 스프라이트 내 ID 충돌 방지 방안 검토 필요

리포지터리 내에서 <linearGradient> 등 ID를 사용하는 SVG 파일이 확인되었습니다 (apps/landing/public/vite.svg, apps/client/public/vite.svg). 스프라이트로 병합 시 전역 ID 충돌 가능성이 있으므로, 아래와 같은 보완을 권장드립니다.

• packages/design-system/svgo.config.mjs
prefixIds 플러그인 추가하여 파일명 기반으로 id에 고유 prefix 부여
• 또는 아이콘 소스 단계에서 id 충돌 방지 규칙(네이밍 컨벤션) 도입

예시 (svgo.config.mjs):

 plugins: [
+  {
+    name: 'prefixIds',
+    params: {
+      prefix: ({ path }) => path
+        .split('/')
+        .pop()
+        .replace(/\.svg$/, '') + '-'
+    }
+  },
   { name: 'preset-default', params: { overrides: { removeViewBox: false } } },
   { name: 'removeDimensions' },
 ],
packages/design-system/src/icons/iconNames.ts (1)

7-7: 생성 스크립트와 괄호 표기 일관성 유지 권장

현재 파일은 (typeof iconNames)[number] 형태인데, 생성 스크립트는 typeof iconNames[number]를 사용합니다. 둘 다 동작은 같지만, 불필요한 변경(churn)을 막기 위해 생성 스크립트 쪽을 본 파일 스타일로 맞추는 것을 권장합니다.

packages/design-system/vite.config.ts (1)

12-13: 상대 경로 대신 절대 경로 사용으로 견고성 향상

플러그인에 따라 iconDirs는 절대 경로가 더 안전합니다. __dirname 기반 절대 경로로 변경을 권장합니다.

적용 제안(diff):

-      iconDirs: ['src/icons/source'],
+      iconDirs: [path.resolve(__dirname, 'src/icons/source')],
packages/design-system/src/icons/scripts/generate-icon-list.ts (3)

11-14: 생성 결과의 결정성을 위해 정렬 추가 권장

OS/파일시스템에 따라 readdirSync 결과 순서가 달라질 수 있어, 아이콘 추가/삭제와 무관한 불필요한 diff가 발생할 수 있습니다. 정렬을 추가해 빌드 결정성을 확보하세요.

적용 제안(diff):

-const files = readdirSync(ICON_DIR).filter((file) => file.endsWith('.svg'));
+const files = readdirSync(ICON_DIR)
+  .filter((file) => file.endsWith('.svg'))
+  .sort((a, b) => a.localeCompare(b));

15-18: 타입 표기 스타일을 생성물(iconNames.ts)과 일치시키세요

현재 스크립트는 typeof iconNames[number]를 생성하지만, 산출물은 (typeof iconNames)[number] 형태입니다. 일관성을 위해 후자 형태로 맞추는 것을 권장합니다.

적용 제안(diff):

-const content = `// 이 파일은 자동 생성 파일입니다. (직접 수정 금지)
-export const iconNames = ${JSON.stringify(iconNames)} as const;
-export type IconName = typeof iconNames[number];
-`;
+const content = `// 이 파일은 자동 생성 파일입니다. (직접 수정 금지)
+export const iconNames = ${JSON.stringify(iconNames)} as const;
+export type IconName = (typeof iconNames)[number];
+`;

8-10: 예외 처리(존재하지 않는 디렉터리 등) 최소 보강 제안

ICON_DIR이 존재하지 않거나 비어 있는 경우를 대비해 간단한 가드만 두어도 DX가 좋아집니다. 실패 시 친절한 에러 메시지 또는 빈 리스트를 생성하도록 처리할 수 있습니다.

원하시면 try/catch + 안내 메시지 패턴으로 보강된 버전을 제안드리겠습니다.

packages/design-system/package.json (1)

38-38: 빌드 전용 도구는 devDependencies로 이동 권장 (런타임 오염/설치 비용 절감)

@pivanov/vite-plugin-svg-spritesvgo는 빌드/생성 단계에서만 사용됩니다. 라이브러리 소비자 앱에까지 불필요하게 설치되지 않도록 devDependencies로 옮기는 것을 권장합니다.

다음과 같이 이동 가능합니다:

   "devDependencies": {
+    "@pivanov/vite-plugin-svg-sprite": "^3.1.3",
+    "svgo": "^4.0.0",
     ...
   },
   "dependencies": {
-    "@pivanov/vite-plugin-svg-sprite": "^3.1.3",
     "@radix-ui/react-slot": "^1.2.3",
     ...
-    "svgo": "^4.0.0",
     "tailwind-merge": "^3.3.1",
     "tw-animate-css": "^1.3.7"
   }

Also applies to: 45-45

packages/design-system/src/icons/index.ts (1)

1-1: 아이콘 타입 재노출 제안: 소비자 단 타입 접근성 개선

Icon 컴포넌트만 공개하면 소비자 쪽에서 IconName 타입을 직접 사용하기 어렵습니다. ./icons 엔트리에서 타입을 함께 재노출하면 DX가 개선됩니다.

-export { Icon } from './components/icon';
+export { Icon } from './components/icon';
+export type { IconName } from './iconNames';
packages/design-system/src/icons/components/icon.tsx (5)

52-53: 기본 크기(24)와 PR 사용설명서(기본 20px) 불일치

PR 안내에선 기본 width/height가 20px이라고 되어 있으나, 컴포넌트 기본값은 24입니다. 문서 또는 코드 중 하나를 정합화해 주세요.

문서 기준(20px)으로 맞출 경우:

-  const w = width ?? size ?? 24;
-  const h = height ?? size ?? 24;
+  const w = width ?? size ?? 20;
+  const h = height ?? size ?? 20;

55-63: 회전 클래스 분기 간소화 제안

중첩 삼항 대신 매핑 객체로 간결하게 표현하면 가독성과 유지보수가 좋아집니다.

-  const rotateClass =
-    rotate === 90
-      ? 'rotate-90'
-      : rotate === 180
-        ? 'rotate-180'
-        : rotate === 270
-          ? 'rotate-[270deg]'
-          : '';
+  const rotateMap: Record<NonNullable<IconRotate>, string> = {
+    90: 'rotate-90',
+    180: 'rotate-180',
+    270: 'rotate-[270deg]',
+  };
+  const rotateClass = rotate ? rotateMap[rotate] : '';

66-77: 접근성 보강: aria-hidden 자동 판별 및 role 설정

  • 현재 기본 ariaHidden = true라서, 소비자가 aria-label을 전달해도 스크린리더에 노출되지 않는 혼선이 생길 수 있습니다.
  • role="img"는 접근성 도구가 의미를 파악하는 데 도움이 됩니다(장식적일 때는 숨김 유지).

다음과 같이 개선을 권장합니다.

 export const Icon = ({
   ...
-  ariaHidden = true,
+  ariaHidden = true,
   ...rest
 }: IconProps) => {
   ...
-  return (
+  // aria-label, aria-labelledby, title 중 하나라도 있으면 강제로 노출
+  const hasAccessibleName =
+    !!(rest['aria-label'] || rest['aria-labelledby'] || rest.title);
+  const computedAriaHidden = ariaHidden && !hasAccessibleName;
+
+  return (
     <svg
       width={typeof w === 'number' ? `${w}px` : w}
       height={typeof h === 'number' ? `${h}px` : h}
       className={combined}
-      style={color ? { color: `var(--color-${color})` } : undefined}
-      aria-hidden={ariaHidden}
+      style={color ? { color: `var(--color-${color})` } : undefined}
+      role={computedAriaHidden ? undefined : 'img'}
+      aria-hidden={computedAriaHidden}
+      focusable="false"
       {...rest}
     >
       <use href={`#icon-${name}`} />
     </svg>
   );

66-77: 색상 속성의 실효성 점검: currentColor 미사용 아이콘에서 color prop이 무의미할 수 있음

현재 <svg style={{ color: var(--color-XXX) }} />만 설정되어 있고, 내부 심볼이 fill="currentColor"/stroke="currentColor"를 사용하지 않는다면 색상 변경이 적용되지 않습니다. PR 설명에 "currentColor 자동 변경은 적용하지 않음"이라고 되어 있으므로, 최소한의 일관성을 위해 다음 중 하나를 권장합니다.

옵션 A(안전, 부분 효과): <svg> 기본 fill을 currentColor로 지정하여, 명시적 fill이 없는 path에는 색이 적용되도록 합니다.

-    <svg
+    <svg
       ...
-      style={color ? { color: `var(--color-${color})` } : undefined}
+      style={color ? { color: `var(--color-${color})` } : undefined}
+      fill="currentColor"
       ...
     >

옵션 B(선택 기능화): forceCurrentColor 같은 prop을 추가해 <svg> 내부에 style 혹은 <style>* { fill: currentColor; stroke: currentColor }를 주입(기본값 false). 컬러 아이콘을 강제로 단색화할 수 있어 주의가 필요합니다.

적용 시, 기존 컬러 아이콘에 대한 영향 범위를 반드시 확인해 주세요.


41-50: ariaHidden 커스텀 prop vs. aria-hidden 전달 가능성 중복

IconPropsariaHidden(camelCase)을 두면서, 동시에 ...restaria-hidden(kebab-case)을 전달받으면 설정 충돌 여지가 있습니다. 하나의 경로만 권장합니다.

  • 방안 1: 커스텀 ariaHidden 제거하고, 소비자에게 표준 aria-hidden 사용을 안내.
  • 방안 2: 커스텀 decorative?: boolean으로 변경(우선순위: decorative > aria-hidden > auto).
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5dc8aeb and 4b9d15a.

⛔ Files ignored due to path filters (4)
  • packages/design-system/src/icons/source/dotori.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/down_icon.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_arrow_down_white.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • packages/design-system/package.json (1 hunks)
  • packages/design-system/src/icons/components/icon.tsx (1 hunks)
  • packages/design-system/src/icons/iconNames.ts (1 hunks)
  • packages/design-system/src/icons/index.ts (1 hunks)
  • packages/design-system/src/icons/scripts/generate-icon-list.ts (1 hunks)
  • packages/design-system/svgo.config.mjs (1 hunks)
  • packages/design-system/tsconfig.json (1 hunks)
  • packages/design-system/vite.config.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-04T10:12:01.690Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#10
File: apps/landing/src/index.css:1-1
Timestamp: 2025-07-04T10:12:01.690Z
Learning: In TailwindCSS v4, the import "tailwindcss"; syntax is the new recommended approach that replaces the three separate tailwind directives (tailwind base;, tailwind components;, tailwind utilities;). This is used with the tailwindcss/vite plugin.

Applied to files:

  • packages/design-system/vite.config.ts
🧬 Code Graph Analysis (2)
packages/design-system/src/icons/scripts/generate-icon-list.ts (1)
packages/design-system/src/icons/iconNames.ts (1)
  • iconNames (2-6)
packages/design-system/src/icons/components/icon.tsx (1)
packages/design-system/src/icons/iconNames.ts (1)
  • IconName (7-7)
🔇 Additional comments (3)
packages/design-system/svgo.config.mjs (1)

1-9: SVGO 기본값 구성이 목적에 잘 맞습니다 (viewBox 유지 + 크기 제거)

multipass + preset-default(override removeViewBox:false) + removeDimensions 조합이 스프라이트 기반 아이콘에 적합합니다. 👍

packages/design-system/src/icons/iconNames.ts (1)

1-7: 자동 생성 결과가 안정적이며 타입 유틸리티 사용이 적절합니다

튜플(as const) + 유니온 타입 파생 패턴이 적절합니다. 아이콘 파이프라인과도 잘 맞습니다.

packages/design-system/package.json (1)

29-29: 개발 도구 추가 반영 LGTM

@vitejs/plugin-reacttsx 추가는 목적에 부합하며 문제 없어 보입니다.

Also applies to: 32-32

Comment on lines +16 to +17
"icons:clean": "svgo -f src/icons/source --config=./svgo.config.mjs --multipass",
"generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

아이콘 스크립트 체인 및 Prettier 의존성 확인 필요

  • icons:cleangenerate:icons를 함께 실행하는 편의 스크립트(예: icons)를 추가하면 DX가 좋아집니다.
  • generate:icons에서 prettier --write를 호출하는데, 이 패키지(또는 워크스페이스 루트)에 Prettier가 설치되어 있어야 합니다. 현재 이 패키지의 devDependencies에는 Prettier가 보이지 않습니다.

확인을 위해 다음 스크립트를 실행해 주세요. 목적: (1) 이 리포 내 Prettier 설치 여부, (2) svgo 설정 파일 존재 여부, (3) 아이콘 리스트 스크립트 존재 여부.

추가 제안(선택):

   "scripts": {
     ...
-    "icons:clean": "svgo -f src/icons/source --config=./svgo.config.mjs --multipass",
-    "generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
+    "icons:clean": "svgo -f src/icons/source --config=./svgo.config.mjs --multipass",
+    "generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
+    "icons": "pnpm icons:clean && pnpm generate:icons",
     ...
   }

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Prettier 설치 확인 =="
node -e "console.log(require.resolve('prettier'))" 2>/dev/null && echo "prettier: OK (resolve 가능)" || echo "prettier: NOT FOUND"

echo
echo "== SVGO 설정 파일 존재 확인 =="
if [ -f packages/design-system/svgo.config.mjs ]; then
  echo "packages/design-system/svgo.config.mjs: OK"
else
  echo "packages/design-system/svgo.config.mjs: NOT FOUND"
fi

echo
echo "== 아이콘 생성 스크립트 존재 확인 =="
if [ -f packages/design-system/src/icons/scripts/generate-icon-list.ts ]; then
  echo "generate-icon-list.ts: OK"
else
  echo "generate-icon-list.ts: NOT FOUND"
fi

Length of output: 590


디자인 시스템 패키지에 Prettier 설치 및 아이콘 스크립트 통합 필요

검증 결과:

  • Prettier: 미설치 → generate:icons 실행 시 prettier 명령을 찾지 못해 실패함
  • SVGO 설정 파일: packages/design-system/svgo.config.mjs 존재
  • 아이콘 생성 스크립트: packages/design-system/src/icons/scripts/generate-icon-list.ts 존재

해결 방안:

  • packages/design-systemdevDependencies에 Prettier 추가 또는 워크스페이스 루트에 Prettier 설치
  • (선택) 아이콘 작업을 한 번에 실행할 수 있도록 스크립트 병합

예시 변경:

 "scripts": {
   …
   "icons:clean": "svgo -f src/icons/source --config=./svgo.config.mjs --multipass",
   "generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
+  "icons": "pnpm icons:clean && pnpm generate:icons",
   …
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"icons:clean": "svgo -f src/icons/source --config=./svgo.config.mjs --multipass",
"generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
"icons:clean": "svgo -f src/icons/source --config=./svgo.config.mjs --multipass",
"generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
"icons": "pnpm icons:clean && pnpm generate:icons",
🤖 Prompt for AI Agents
packages/design-system/package.json lines 16-17: the generate:icons script
invokes the prettier CLI which is not installed in this package (causing
failures); add prettier to packages/design-system devDependencies (or ensure the
monorepo root has prettier and the package can access it) and update
package.json accordingly; optionally merge the two icon scripts into one (e.g.,
a single "icons:generate" script that runs the tsx generation then prettier) so
icon generation is atomic and the CLI is available when the script runs.

@@ -0,0 +1,78 @@
import type { IconName } from '../iconNames';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

React 네임스페이스 타입 직접 사용으로 인한 TS 빌드 오류 가능성

React.SVGProps를 사용하고 있지만 React 타입을 임포트하지 않았습니다. 환경에 따라 "Cannot find namespace 'React'" 오류가 발생할 수 있습니다. 네임스페이스 의존을 피하고 SVGProps를 명시 임포트하는 쪽이 안전합니다.

-import type { IconName } from '../iconNames';
+import type { IconName } from '../iconNames';
+import type { SVGProps } from 'react';

 ...

-interface IconProps extends React.SVGProps<SVGSVGElement> {
+interface IconProps extends SVGProps<SVGSVGElement> {

Also applies to: 30-39

🤖 Prompt for AI Agents
In packages/design-system/src/icons/components/icon.tsx around line 1 (and
similarly affecting lines 30-39), the code uses the React namespace type
React.SVGProps without importing React which can trigger "Cannot find namespace
'React'" in some TS setups; instead add a type-only import "import type {
SVGProps } from 'react'" and replace all occurrences of React.SVGProps with
SVGProps so the file relies on explicit type imports rather than the React
namespace.

Comment on lines +75 to +76
<use href={`#icon-${name}`} />
</svg>
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

스프라이트 주입 책임 위치 확인: 소비 앱에서 심볼 미주입 시 렌더 실패

<use href="#icon-${name}" />는 DOM 어딘가에 <symbol id="icon-${name}" />가 이미 주입되어 있어야 동작합니다. 현재 스프라이트 주입을 packages/design-system/vite.config.ts의 플러그인에 의존한다면, 디자인시스템을 소비하는 앱의 빌드 파이프라인에서는 심볼이 주입되지 않을 수 있습니다(라이브러리 번들 vs. 앱 번들 경계 이슈).

권장 옵션:

  • 소비 앱의 Vite 설정에도 동일한 플러그인을 추가하고, iconDirs 경로를 라이브러리 번들 산출물/리소스로 일치시킵니다(문서화 필수).
  • 혹은 라이브러리에서 스프라이트 파일을 정적 자산으로 배포하고, 소비자가 HTML에 명시적으로 포함하거나, 라이브러리 제공 SpriteHost 컴포넌트를 앱 루트에서 한 번 렌더해 <symbol>들을 주입합니다.

다음 스크립트로 현재 리포에서 플러그인 적용 위치를 점검해 주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== vite.config.ts 내 svg-sprite 플러그인 사용 위치 검색 =="
fd -t f vite.config.ts | while read -r f; do
  echo "--- $f ---"
  rg -nP "@pivanov/vite-plugin-svg-sprite|svgSpritePlugin" -n -C2 "$f" || true
done

Length of output: 1259


스프라이트 주입 위치 검토 필요

검토 결과, SVG 스프라이트 플러그인은 packages/design-system/vite.config.ts에서만 적용되어 있으며, 소비 앱(apps/client, apps/extension, apps/landing)의 Vite 설정에는 전혀 반영되어 있지 않습니다. 이대로 두면 <use href="#icon-{name}" />가 렌더링되지 않아 아이콘이 표시되지 않습니다.

영향 받는 파일:

  • apps/client/vite.config.ts (svgSpritePlugin 미적용)
  • apps/extension/vite.config.ts (미적용)
  • apps/landing/vite.config.ts (미적용)
  • packages/design-system/vite.config.ts (적용됨)

권장 조치:

  • 소비 앱의 Vite 설정에도 @pivanov/vite-plugin-svg-sprite 플러그인을 추가하고, iconDirs 옵션을 디자인시스템의 아이콘 소스 경로와 일치시켜 문서화합니다.
  • 또는 디자인시스템에서 완성된 스프라이트 파일을 정적 자산으로 배포하여 소비자가 HTML에 직접 포함하거나, 라이브러리 내에 SpriteHost 컴포넌트를 제공해 앱 루트에서 한 번만 렌더링하도록 구현합니다.
🤖 Prompt for AI Agents
packages/design-system/src/icons/components/icon.tsx around lines 75-76: the
component uses <use href={`#icon-${name}`} /> but the SVG sprite plugin is only
configured in packages/design-system/vite.config.ts so consumer apps won't have
the generated sprite and icons won't render; update each consumer app vite
config (apps/client/vite.config.ts, apps/extension/vite.config.ts,
apps/landing/vite.config.ts) to include @pivanov/vite-plugin-svg-sprite with
iconDirs pointed to the design-system icons source (match the path used in
packages/design-system), and document this requirement in the design-system
README; alternatively, if you prefer a library-side fix, build and publish the
compiled sprite as a static asset or add a SpriteHost React component in the
design-system that renders the generated sprite once at app root and document
how to include it.

Comment on lines +8 to +16
plugins: [
react(),
tailwindcss(),
svgSpritePlugin({
iconDirs: ['src/icons/source'],
symbolId: 'icon-[name]',
inject: 'body-last',
}),
],
Copy link

@coderabbitai coderabbitai bot Aug 20, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

라이브러리 내부에서 스프라이트를 주입하면 소비 애플리케이션에서는 주입이 이뤄지지 않을 수 있습니다

현재 플러그인은 design-system 패키지의 Vite 설정에만 추가되어 있습니다. 이 설정은 라이브러리 빌드에는 영향을 주지만, 이 라이브러리를 사용하는 실제 앱(소비자)의 HTML에는 스프라이트가 자동 주입되지 않습니다. 결과적으로 소비 앱에서 <use href="#icon-...">가 참조할 심볼이 존재하지 않아 아이콘이 표시되지 않을 수 있습니다.

대안:

  • 소비 애플리케이션의 Vite 설정에도 동일 플러그인을 추가하여 주입을 앱에서 수행.
  • 또는 라이브러리에서 스프라이트를 런타임으로 주입하는 Provider/컴포넌트를 제공(최초 마운트 시 DOM에 삽입).
  • 또는 빌드 타임에 sprite.svg 자산을 생성해, 소비 앱이 HTML에 직접 포함하도록 가이드.

지금 상태는 소비 앱 관점에서 “심볼 미주입” 위험이 높으므로 보완이 필요합니다.

원하시면 소비 앱용 Provider 컴포넌트/가이드를 함께 제안드리겠습니다.

소비 앱 쪽에 동일 플러그인이 설정되어 있는지 확인:


🏁 Script executed:

#!/bin/bash
# 레포 전체에서 해당 플러그인 사용 여부 확인
rg -n -C2 -P "@pivanov/vite-plugin-svg-sprite|svgSpritePlugin\\("

Length of output: 2563


소비 애플리케이션 Vite 설정에 SVG 스프라이트 플러그인 미적용 – 심볼 주입 누락 위험

현재 packages/design-system/vite.config.ts 에는 svgSpritePlugin 이 적용되어 있으나, 레포 전체 검색 결과 소비 애플리케이션(apps/extension 등)의 Vite 설정 파일에서는 플러그인 사용이 확인되지 않습니다. 이로 인해 <use href="#icon-...">가 참조하는 SVG 심볼이 소비 앱 HTML에 삽입되지 않아 아이콘이 표시되지 않을 수 있습니다.

조치 방안:

  • 소비 애플리케이션 Vite 설정(apps/extension/vite.config.ts 등)에 svgSpritePlugin({ iconDirs: […], symbolId: 'icon-[name]', inject: 'body-last' }) 추가
  • 또는 런타임에서 스프라이트를 DOM에 삽입하는 Provider/컴포넌트 제공 (초기 마운트 시)
  • 또는 빌드 시점에 sprite.svg 자산을 생성해, 소비 앱이 HTML에 직접 포함하도록 문서화

필요 시 소비 앱용 Provider 컴포넌트 및 가이드 작성도 지원 가능합니다.

🤖 Prompt for AI Agents
In packages/design-system/vite.config.ts around lines 8-16 the svgSpritePlugin
is configured but consumer apps (e.g., apps/extension) do not apply this plugin
so SVG symbols may not be injected into their HTML; update each consumer Vite
config (e.g., apps/extension/vite.config.ts) to include svgSpritePlugin with the
same options (iconDirs pointing to the design-system icons, symbolId:
'icon-[name]', inject: 'body-last'), or alternatively implement a runtime
Provider/component that injects the sprite into the DOM on initial mount, or add
a build step that emits a shared sprite.svg and document adding it into consumer
HTML—pick one approach and apply consistently across consumer app configs or add
the runtime Provider and corresponding docs/tests.

Copy link
Member

Choose a reason for hiding this comment

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

이 부분 체크해보셔야 할 것 같아요!
apps 3개에서 vite.config.ts에 따로 svgSpritePlugin 설정 안 해도 저 아이콘 가져다 쓰는 거 문제 없나요??

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

@constantly-dev 좋은 지적이에요! 이 부분 확실히 체크해봐야겠습니다. SVG 스프라이트 설정이 디자인 시스템에만 있으면 실제 앱에서 아이콘이 안 보일 수 있거든요.


🏁 Script executed:

#!/bin/bash
# 1. apps 디렉터리 구조 확인
echo "=== Apps 디렉터리 구조 ==="
find apps -name "vite.config.*" -type f 2>/dev/null | head -10

echo -e "\n=== 각 앱의 Vite 설정에서 svgSpritePlugin 사용 여부 확인 ==="
rg -n -C3 -P "svgSpritePlugin|@pivanov/vite-plugin-svg-sprite" apps/ || echo "앱들에서 svgSpritePlugin 설정을 찾을 수 없습니다."

echo -e "\n=== 앱들 목록 ==="
ls -la apps/

Length of output: 1136


🏁 Script executed:

#!/bin/bash
# extension 앱에서 svgSpritePlugin이 설치되어 있으니 vite.config.ts에서 실제 사용하는지 확인
echo "=== apps/extension/vite.config.ts 내용 ==="
cat apps/extension/vite.config.ts

echo -e "\n=== apps/client/vite.config.ts 내용 ==="
cat apps/client/vite.config.ts

echo -e "\n=== apps/landing/vite.config.ts 내용 ==="
cat apps/landing/vite.config.ts

echo -e "\n=== 각 앱에서 design-system 의존성 확인 ==="
echo "-- apps/extension/package.json --"
rg -n "design-system" apps/extension/package.json || echo "design-system 의존성 없음"

echo "-- apps/client/package.json --"
rg -n "design-system" apps/client/package.json || echo "design-system 의존성 없음"

echo "-- apps/landing/package.json --"
rg -n "design-system" apps/landing/package.json || echo "design-system 의존성 없음"

Length of output: 2550


예상했던 대로 문제가 있네요! 🚨

현재 상황 분석

  1. 3개 앱 모두 design-system 의존성은 있음: apps/extension, apps/client, apps/landing
  2. 하지만 어느 앱도 svgSpritePlugin 설정이 없음
  3. extension 앱@pivanov/vite-plugin-svg-sprite 패키지를 설치해뒀지만 실제 vite.config.ts에서 사용하지 않음
  4. client, landing 앱은 vite.config.ts에 // TODO: svg 설정 추가 주석이 있음

문제점

현재 설정으로는 아이콘이 표시되지 않습니다:

  • Icon 컴포넌트가 <use href="#icon-{name}" />로 스프라이트를 참조하지만
  • 실제 앱의 DOM에는 해당 심볼들이 주입되지 않음
  • 결과: 빈 아이콘 또는 깨진 아이콘

해결 방안

각 앱의 vite.config.tssvgSpritePlugin 설정을 추가해야 합니다:

1. apps/extension/vite.config.ts 수정

import svgSpritePlugin from '@pivanov/vite-plugin-svg-sprite';
// ... 기존 imports

export default defineConfig({
  plugins: [
    react(),
    tsconfigPaths({
      projects: [resolve(__dirname, '../../tsconfig.json')],
    }),
    tailwindcss(),
    svgSpritePlugin({
      iconDirs: ['../../packages/design-system/src/icons/source'],
      symbolId: 'icon-[name]',
      inject: 'body-last',
    }),
    crx({ manifest }), 
  ],
  // ... 나머지 설정
});

2. apps/client/vite.config.ts, apps/landing/vite.config.ts에도 동일 설정 추가

import svgSpritePlugin from '@pivanov/vite-plugin-svg-sprite';
// ... 기존 imports

export default defineConfig({
  plugins: [
    react(), 
    tsconfigPaths(), 
    tailwindcss(),
    svgSpritePlugin({
      iconDirs: ['../../packages/design-system/src/icons/source'],
      symbolId: 'icon-[name]',
      inject: 'body-last',
    }),
  ],
});

그리고 client, landing 앱의 package.json에도 의존성 추가 필요:

"@pivanov/vite-plugin-svg-sprite": "^3.1.3"

지금 당장 수정하지 않으면 Icon 컴포넌트가 제대로 동작하지 않을 거예요! 👀


🧠 Learnings used
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#10
File: apps/landing/src/index.css:1-1
Timestamp: 2025-07-04T10:12:01.690Z
Learning: In TailwindCSS v4, the import "tailwindcss"; syntax is the new recommended approach that replaces the three separate tailwind directives (tailwind base;, tailwind components;, tailwind utilities;). This is used with the tailwindcss/vite plugin.

Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#10
File: apps/landing/src/index.css:1-1
Timestamp: 2025-07-04T10:12:01.690Z
Learning: In TailwindCSS v4, the import "tailwindcss"; syntax is the new recommended approach that replaces the three separate tailwind directives (tailwind base;, tailwind components;, tailwind utilities;). This single import pulls in all of Tailwind's preflight, components, and utilities in one step and is used with the tailwindcss/vite plugin.

Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.021Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.

@jjangminii jjangminii changed the title Setting(project): svg splite 설정 Setting(project): svg sprite 설정 Aug 20, 2025
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

♻️ Duplicate comments (1)
packages/design-system/package.json (1)

17-17: generate:icons가 Prettier 미설치 시 실패합니다

prettier --write를 호출하지만 이 패키지의 devDependencies에 Prettier가 없습니다. 워크스페이스 루트에 설치되어 있더라도 pnpm 특성상 서브패키지 스크립트에서 바로 prettier 바이너리를 못 찾는 경우가 많아 실패합니다. 이 패키지에 Prettier를 추가하거나, 워크스페이스 루트의 Prettier를 강제로 사용하도록 스크립트를 바꾸세요.

다음 중 하나를 적용하세요.

  • 옵션 A(권장): devDependencies에 Prettier 추가
   "devDependencies": {
     "@pinback/eslint-config": "workspace:*",
     "@pinback/tailwind-config": "workspace:*",
     "@pinback/typescript-config": "workspace:*",
     "@tailwindcss/vite": "^4.1.12",
     "@turbo/gen": "^2.5.0",
     "@types/node": "^22.15.3",
     "@types/react": "19.1.0",
     "@types/react-dom": "19.1.1",
     "@vitejs/plugin-react": "^4.5.2",
     "eslint": "^9.33.0",
     "tailwindcss": "^4.1.12",
     "tsx": "^4.20.4",
     "typescript": "5.9.2",
     "typescript-eslint": "^8.39.1",
-    "vite": "^7.1.2"
+    "vite": "^7.1.2",
+    "prettier": "^3.3.3"
   },
  • 옵션 B: 루트 Prettier를 사용하도록 스크립트 변경
-    "generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
+    "generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && pnpm -w exec prettier --write packages/design-system/src/icons/iconNames.ts",

필요하면 루트에 Prettier가 있는지 확인하는 검증 스크립트도 제공할 수 있습니다.

🧹 Nitpick comments (3)
packages/design-system/package.json (2)

39-39: 빌드 전용 플러그인은 devDependencies로 이동하세요

@pivanov/vite-plugin-svg-sprite는 Vite 빌드 타임에만 사용됩니다. runtime dependencies에 두면 소비자 앱 설치 용량 및 종속성 표면이 불필요하게 늘어납니다.

의존성 섹션에서 제거:

-    "@pivanov/vite-plugin-svg-sprite": "^3.1.3",

devDependencies로 이동:

   "devDependencies": {
+    "@pivanov/vite-plugin-svg-sprite": "^3.1.3",
     "@pinback/eslint-config": "workspace:*",
     ...
   }

46-46: SVGO도 devDependencies가 적절합니다

svgo는 아이콘 소스를 전처리하는 도구이므로 런타임 의존성일 필요가 없습니다. devDependencies로 옮겨 설치/배포 표면을 줄이세요.

dependencies에서 제거:

-    "svgo": "^4.0.0",

devDependencies에 추가:

   "devDependencies": {
+    "svgo": "^4.0.0",
     "@pinback/eslint-config": "workspace:*",
     ...
   }
packages/design-system/src/icons/iconNames.ts (1)

2-14: 아이콘 네이밍 컨벤션 점검: ‘disable’ vs ‘disabled’

여러 항목이 ‘disable’ 형태를 사용합니다. 팀 컨벤션이 ‘disabled’라면 스크립트 단계에서 일괄 정규화(예: kebab/camel→snake, 상태 접미사 통일)를 고려하세요. 반대로 디자이너 산출물 파일명이 규칙이라면 현재 상태도 OK입니다. 결정만 명문화되면 됩니다.

원하면 generate-icon-list.ts에 다음과 같은 후처리를 추가하는 패치를 제안해 드리겠습니다:

  • 파일명에서 상태 토큰을 파싱해 ‘disabled’로 치환
  • 알파벳/숫자/언더스코어만 허용하도록 sanitize
  • 정렬(sorting) 고정으로 PR 디프 변동 최소화
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4b9d15a and 245fadb.

⛔ Files ignored due to path filters (11)
  • packages/design-system/src/icons/source/ic_arrow_down_active.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_arrow_down_disable.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_bookmark_active.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_bookmark_disable.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_clock_active.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_clock_disable.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_close.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_details_category.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_details_disable.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_info.svg is excluded by !**/*.svg
  • packages/design-system/src/icons/source/ic_plus.svg is excluded by !**/*.svg
📒 Files selected for processing (3)
  • packages/design-system/package.json (1 hunks)
  • packages/design-system/src/icons/components/icon.tsx (1 hunks)
  • packages/design-system/src/icons/iconNames.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/design-system/src/icons/components/icon.tsx
🔇 Additional comments (6)
packages/design-system/package.json (4)

16-16: SVGO 최적화 스크립트 구성 좋습니다

--config--multipass 플래그 사용이 목적에 부합합니다. 소스 경로도 패키지 기준 상대경로로 올바릅니다.


19-19: DX 향상: 단일 진입점 스크립트 추가 좋습니다

pnpm icons로 정리+생성을 한 번에 수행할 수 있어 작업 흐름이 명확해집니다.


30-30: 변경 영향 없음

devDependency 순서 변경은 기능적 영향이 없습니다.


33-33: tsx 도입 적절합니다

경량 TS 실행기에 tsx를 사용해 아이콘 목록 생성 스크립트를 구동하는 접근이 적절합니다.

packages/design-system/src/icons/iconNames.ts (2)

1-1: 자동 생성 경고 주석 좋습니다

수동 편집 방지를 명확히 해 협업 실수를 줄입니다. 생성 스크립트에서 동일 주석 유지도 확인 바랍니다.


14-15: as const + 유니온 타입 패턴 적절합니다

런타임 배열과 타입 유니온을 동기화하는 안전한 패턴입니다. 컴포넌트 prop에 IconName을 적용하면 오타를 컴파일 타임에 차단할 수 있습니다.

Copy link
Collaborator

@jllee000 jllee000 left a comment

Choose a reason for hiding this comment

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

https://www.reddit.com/r/css/comments/x940jt/change_svg_color_with_help_from_css_filter/?tl=ko

currentcolor 넣는 고민에 대해서 저도 찾아보니, 캐릭터 이미지처럼 여러색이 들어간 경우는 색상변경 제어를 넣진 않는것같고

단색인 svg 경우에 뭐 호버에 따라 색상이 달라진다든지의 경우엔 css필터?? 뭐 이런거 넣는 얘기도 있던데, 저도 더 좋은 방안 찾아보겠습니당


const iconNames = files.map((file) => basename(file, '.svg'));

const content = `// 이 파일은 자동 생성 파일입니다. (직접 수정 금지)
Copy link
Collaborator

Choose a reason for hiding this comment

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

이거 generate빌드하면 그때 그 자동 생성되는 구간이였나용??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

generate빌드하면 이 파일의 함수들로 iconsName파일에 자동생성됩니당


type IconRotate = 90 | 180 | 270;

type IconColor =
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
Member

@constantly-dev constantly-dev left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~~
prettier 설정이나 svgo를 통해 width/height 자동으로 지워주는 설정 때문에 훨씬 개발 생산성이 높아질 것 같아요!! 최고입니다 👍

몇 개 코멘트 남겼으니 확인 부탁드려요 ~

"check-types": "tsc --noEmit",
"generate:component": "turbo gen react-component"
"icons:clean": "svgo -f src/icons/source --config=./svgo.config.mjs --multipass",
"generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
Copy link
Member

Choose a reason for hiding this comment

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

저번에 문제 생긴 prettier 부분을 이렇게 해결해주셨네요 👍

Comment on lines 6 to 28
type IconColor =
| 'main0'
| 'main100'
| 'main200'
| 'main300'
| 'main400'
| 'main500'
| 'main600'
| 'secondary'
| 'error400'
| 'success400'
| 'white'
| 'black'
| 'gray0'
| 'gray100'
| 'gray200'
| 'gray300'
| 'gray400'
| 'gray500'
| 'gray600'
| 'gray700'
| 'gray800'
| 'gray900';
Copy link
Member

Choose a reason for hiding this comment

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

확실히 tailwind v4에서 css 형식으로 token 설정을 해주니까 이런 부분도 다 정적으로 박아야 하네요.
해당 icon컴포넌트랑 twMerge 함수 부분도 token 정보를 필요로 해서 이 부분을 중앙화 할 방법을 꼭 생각해내야 할 것 같아요.
같이 고민해봐요 👍

Comment on lines +52 to +53
const w = width ?? size ?? 20;
const h = height ?? size ?? 20;
Copy link
Member

Choose a reason for hiding this comment

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

fallback까지 굳굳 👍

Comment on lines +8 to +16
plugins: [
react(),
tailwindcss(),
svgSpritePlugin({
iconDirs: ['src/icons/source'],
symbolId: 'icon-[name]',
inject: 'body-last',
}),
],
Copy link
Member

Choose a reason for hiding this comment

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

이 부분 체크해보셔야 할 것 같아요!
apps 3개에서 vite.config.ts에 따로 svgSpritePlugin 설정 안 해도 저 아이콘 가져다 쓰는 거 문제 없나요??

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: 1

🧹 Nitpick comments (8)
package.json (1)

13-13: pnpm.overrides로 플러그인 버전 고정 및 devDependency 중복 제거 권장

현재 레포 내 모든 package.json(루트, apps/extension, apps/landing, apps/client, packages/design-system)에서
"@pivanov/vite-plugin-svg-sprite": "^3.1.3"가 동일하게 선언되어 있어(스크립트 검증 완료) 버전 드리프트는 없습니다.
하지만 향후 패키지 추가·업데이트 시 버전 관리 편의성을 위해 pnpm.overrides에 고정해두는 것을 권장드립니다.

또한, 루트와 각 패키지 모두에 중복 선언되어 있어 유지보수성이 떨어집니다. 팀 규칙에 따라 아래 중 한 가지 방식을 선택하여 통일해주세요.

  • 각 앱이 자체적으로 선언
  • 루트 한 곳에서만 선언

수정 위치 및 제안 diff:

  • 파일: package.json (루트)
   "pnpm": {
     "overrides": {
-      "vite": "7.1.2"
+      "vite": "7.1.2",
+      "@pivanov/vite-plugin-svg-sprite": "^3.1.3"
     }
   },
  • 각 하위 package.json에서 @pivanov/vite-plugin-svg-sprite devDependency 제거 또는 루트에서만 선언하는 쪽으로 정리
apps/landing/package.json (1)

17-17: 버전 일관성 확보를 위해 루트 overrides 활용 권장

apps/landing/package.json의 pnpm.overrides를 확인해보니, 현재는 vite만 고정되어 있어 @pivanov/vite-plugin-svg-sprite에 대한 버전 고정이 적용되지 않습니다.
하나의 워크스페이스 내에서 플러그인 버전을 일관되게 관리하려면, 루트 package.jsonpnpm.overrides에 다음과 같이 해당 플러그인 버전을 명시해두시는 것을 권장드립니다.

  • 확인 커맨드:

    jq -r '.pnpm.overrides' < apps/landing/package.json

    출력 결과:

    {
      "vite": "7.1.2"
    }
    
  • 권장 추가 예시 (루트 package.json):

    {
      "pnpm": {
        "overrides": {
          "@pivanov/vite-plugin-svg-sprite": "3.1.3"
        }
      }
    }

위와 같이 설정하시면, 하위 패키지에서도 동일한 플러그인 버전이 강제 적용되어 중복 선언이나 버전 불일치 문제를 예방할 수 있습니다.

apps/client/vite.config.ts (2)

10-19: 아이콘 FOUC 방지: sprite 주입 위치를 body-first로 고려

현재 inject: 'body-last'는 초기 페인트 시점에 가 심볼보다 먼저 렌더링되면 순간적으로 아이콘이 비어 보일 수 있습니다. 'body-first'로 바꾸면 이 플리커를 줄일 수 있습니다. 기능적으로는 동일합니다.

아래처럼 변경을 제안합니다:

-    svgSpritePlugin({
+    svgSpritePlugin({
       iconDirs: ['src/icons/source'],
       symbolId: 'icon-[name]',
-      inject: 'body-last',
+      inject: 'body-first',
     }),

9-9: TODO 주석 정리

구현이 완료되어 있으므로 해당 TODO는 제거해도 됩니다.

적용 diff:

-  // TODO: svg 설정 추가
apps/extension/package.json (1)

19-19: devDependency로 이동한 점 적절합니다

플러그인은 빌드 시점에만 필요하므로 devDependencies로의 이동이 맞습니다. 루트 overrides로 버전 고정을 추가하면 확실합니다.

apps/landing/vite.config.ts (3)

10-19: 설정은 동작하나, 경로 안정성·ID 충돌 방지·SVGO 일관성 강화를 권장

현 설정으로도 작동합니다만 아래 3가지를 권장드립니다.

  • 절대 경로 사용: OS·워크스페이스 루트 변화에 덜 민감합니다. 문서 예시도 path.resolve(process.cwd(), ...) 사용을 권장합니다. (github.com)
  • symbolId 충돌 방지: 하위 폴더를 사용할 가능성이 있다면 icon-[dir]-[name]로 바꿔 동일 파일명 충돌을 예방하세요. 해당 패턴은 문서의 기본값과도 부합합니다. (github.com)
  • SVGO로 width/height 제거: PR 목표(자동 제거)와 일치하도록 removeDimensions 플러그인을 추가하세요. 플러그인 기본 SVGO 설정은 viewBox를 보존하므로 안전합니다. (github.com)

아래 diff를 적용해 보세요.

   plugins: [
     react(),
     tsconfigPaths(),
     tailwindcss(),
-    svgSpritePlugin({
-      iconDirs: ['src/icons/source'],
-      symbolId: 'icon-[name]',
-      inject: 'body-last',
-    }),
+    svgSpritePlugin({
+      iconDirs: [path.resolve(process.cwd(), 'src/icons/source')],
+      symbolId: 'icon-[dir]-[name]',
+      svgDomId: 'svg-sprite',
+      inject: 'body-last',
+      svgoConfig: {
+        plugins: [{ name: 'removeDimensions' }],
+      },
+    }),
   ],

또한, 위 diff를 사용하려면 상단에 path import가 필요합니다(아래 코드 추가).

import path from 'node:path';

10-19: Optional: 파일 출력이 필요하면 fileName 사용 고려

런타임 HTML 주입(inject)만으로 충분하다면 현 상태 유지가 최적입니다. 다만 정적 파일 캐시(예: CDN)나 SSR 템플릿에서의 명시적 참조가 필요하면 fileName: 'sprite.svg'를 추가해 dist에 산출하도록 할 수 있습니다. 두 방식은 문서 상 공존 가능하지만, 대부분 하나만 사용합니다. (github.com)


9-9: TODO 주석 정리 제안

이제 설정이 추가되었으니 // TODO: svg 설정 추가 주석은 제거해도 좋습니다.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 245fadb and c9a92b7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • apps/client/package.json (1 hunks)
  • apps/client/vite.config.ts (1 hunks)
  • apps/extension/package.json (1 hunks)
  • apps/extension/vite.config.ts (2 hunks)
  • apps/landing/package.json (1 hunks)
  • apps/landing/vite.config.ts (1 hunks)
  • package.json (1 hunks)
  • packages/design-system/src/icons/components/icon.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/client/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/design-system/src/icons/components/icon.tsx
🔇 Additional comments (3)
apps/extension/vite.config.ts (1)

19-23: HTML 주입 순서 및 다중 엔트리 검증 권장

Vite의 transformIndexHtml 훅은 async·sequential 훅으로, plugins 배열 등록 순서와 enforce/order 옵션에 따라 실행 순서가 결정됩니다. (main.vitejs.dev, v2.vitejs.dev)

검증 체크리스트:

  • dist 폴더의 모든 HTML 파일(popup.html, options.html 등)을 열어 <svg> sprite 태그가 주입되었는지 확인
  • 각 페이지에서 <use href="#icon-..."> 사용 시 아이콘이 정상 렌더링되는지 확인
  • content script 또는 shadow DOM 환경에서 inject 위치(body-first/body-last)가 렌더 타이밍에 영향이 없는지 육안 검증

성능 및 초기 페인트 품질 최적화를 위해 inject: 'body-first'로 변경을 권장합니다:

-    svgSpritePlugin({
+    svgSpritePlugin({
      iconDirs: ['src/icons/source'],
      symbolId: 'icon-[name]',
-     inject: 'body-last',
+     inject: 'body-first',
    }),

필요 시 enforce: 'post' 또는 transformIndexHtml({ order: 'post', handler }) 형태로 훅 실행 순서를 명시적으로 조정하세요. 검증 후 문제 없음을 확인해 주시기 바랍니다.

apps/landing/vite.config.ts (2)

15-16: 아이콘 경로 설정 재확인 및 통일 필요

현재 아래 스크립트 확인 결과, 지정된 두 경로 모두 실제 SVG 파일을 포함하고 있지 않습니다.

  • apps/landing/src/icons/source — SVG 파일 없음
  • packages/design-system/src/icons/source — SVG 파일 없음

이로 인해 다음 사항을 점검 및 조치해 주세요:

  • 단일 아이콘 소스 결정
    • 앱 로컬(apps/landing/src/icons/source)을 사용할지
    • 디자인 시스템 패키지(packages/design-system/src/icons/source)의 공용 아이콘만 사용할지

  • 결정된 소스에 맞춰 vite.config.tsiconDirs 값을 업데이트
    • DS 공용 아이콘을 사용할 경우, 워크스페이스 구조에 맞춘 절대 경로 (예: path.resolve(process.cwd(), '../../packages/design-system/src/icons/source')) 설정
    • Vite 개발 서버의 server.fs.allow 옵션에 해당 경로가 포함되어 있는지 확인

위 사항을 반영한 후, 실제 아이콘 파일이 해당 디렉토리에 존재하는지 재확인 부탁드립니다.


5-5: 플러그인 설치 및 버전 일관성 확인 완료

  • apps/landing/package.json (devDependencies): @pivanov/vite-plugin-svg-sprite → ^3.1.3
  • 루트 package.json (devDependencies): @pivanov/vite-plugin-svg-sprite → ^3.1.3

설치 상태와 버전이 양쪽 모두 일치하므로, 해당 코드 변경을 승인합니다.

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 (2)
apps/landing/vite.config.ts (2)

14-18: iconDirs의 상대 경로는 CWD에 민감합니다 → 절대 경로로 안전화 권장

루트에서 빌드/서브패키지에서 빌드 등 실행 위치가 달라질 때 경로 해석 이슈가 생길 수 있습니다. ESM-safe 절대 경로로 바꿔주세요.

다음 diff는 옵션 내부만 변경합니다:

-    svgSpritePlugin({
-      iconDirs: ['../../packages/design-system/src/icons/source'],
+    svgSpritePlugin({
+      iconDirs: [resolve(__dirname, '../../packages/design-system/src/icons/source')],
       symbolId: 'icon-[name]',
       inject: 'body-last',
     }),

위 변경을 위해 파일 상단에 유틸 import/헬퍼를 추가하세요(선택 코드 블록):

// 추가 필요 (파일 상단)
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));

14-18: 제안: symbolId 패턴에 디렉터리명 또는 해시 추가 검토

스크립트 검증 결과 packages/design-system/src/icons/source 내 SVG 파일명은 중복이 없는 것으로 확인되었습니다. 하지만 향후 아이콘 파일 추가 시 이름 충돌 가능성을 사전에 방지하기 위해, symbolId[dir] 또는 [hash] 토큰을 포함하는 방식을 고려해 보시기를 권장드립니다.

  • 토큰 지원 확인

    • @pivanov/vite-plugin-svg-sprite[dir], [name], [hash] 토큰을 지원합니다.
    • [dir]: 아이콘이 위치한 상대 디렉터리명
    • [name]: SVG 파일명(확장자 제외)
    • [hash]: 파일 내용 기반 해시값
  • 예시 변경안

      svgSpritePlugin({
        iconDirs: ['../../packages/design-system/src/icons/source'],
    -   symbolId: 'icon-[name]',
    +   // 디렉터리명-파일명 조합
    +   symbolId: 'icon-[dir]-[name]',
    });

    또는

      svgSpritePlugin({
        iconDirs: ['../../packages/design-system/src/icons/source'],
    +   // 파일명-해시 조합
    +   symbolId: 'icon-[name]-[hash:6]',
      });
  • 추가 확인 사항

    1. 팀 컨벤션 또는 디자인 시스템 가이드에 따른 symbolId 형식
    2. Icon 컴포넌트를 사용하는 모든 소비처에서 변경된 ID 패턴이 정상 동작하는지 테스트

위 제안은 필수가 아닌 권고사항이며, 현재 코드가 문제 없이 작동하는 점을 참고해 주시기 바랍니다.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c9a92b7 and 1e218ed.

📒 Files selected for processing (3)
  • apps/client/vite.config.ts (1 hunks)
  • apps/extension/vite.config.ts (2 hunks)
  • apps/landing/vite.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/client/vite.config.ts
  • apps/extension/vite.config.ts
🔇 Additional comments (2)
apps/landing/vite.config.ts (2)

10-19: 플러그인 구성 순서와 옵션은 전반적으로 적절합니다

react → tsconfigPaths → tailwindcss → svgSprite 순서, inject: 'body-last' 선택 모두 현재 랜딩 앱(use SPA)에는 무리 없습니다. 위 경로/ID 안정화만 반영되면 충분해 보입니다.


5-5: 플러그인 의존성 및 호환성 검증 완료

  • apps/landing와 루트 package.json 모두 devDependencies에 @pivanov/vite-plugin-svg-sprite@^3.1.3가 선언되어 있습니다.
  • pnpm-lock.yaml에서 Vite@7.1.2 환경에서 vite-plugin-svg-sprite@3.1.3이 정상 해상(resolution)된 것을 확인했습니다.
  • 프로젝트가 Vite 7을 사용 중이며, 플러그인도 해당 버전과 호환됨을 lockfile에서 명백히 확인할 수 있습니다.

추가로, CI 및 로컬 빌드에서 SVG 스프라이트 기능이 예상대로 동작하는지만 한 번 더 검증해주시면 됩니다.

@github-actions
Copy link

github-actions bot commented Aug 21, 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 (2)
packages/design-system/package.json (2)

19-19: Prettier 실행 주체 확인(로컬 vs 워크스페이스 루트)

현재 패키지 devDependencies에 prettier가 없는데, 스크립트는 prettier --write를 직접 호출합니다. 루트에 설치되어 있고 pnpm이 PATH로 노출해주는 전제라면 OK지만, 워크스페이스 설정에 따라 실패할 수 있습니다. 두 가지 중 하나로 명확히 하는 것을 권장합니다.

옵션 A(권장, 루트 사용 명시):

-    "generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && prettier --write src/icons/iconNames.ts",
+    "generate:icons": "tsx src/icons/scripts/generate-icon-list.ts && pnpm -w prettier --write src/icons/iconNames.ts",

옵션 B(패키지 로컬 설치):

   "devDependencies": {
+    "prettier": "^3",
     ...
   }

원하시면 워크스페이스 구성에 맞춰 한쪽으로 정리하는 추가 PR 패치 제안 드리겠습니다.


55-55: 빌드/개발 전용 의존성은 devDependencies로 이동 권장

@pivanov/vite-plugin-svg-spritesvgo는 런타임이 아닌 빌드/도구 체인 전용입니다. 라이브러리 소비자 번들 무게와 설치 시간을 줄이기 위해 devDependencies로 이동하는 것을 권장합니다.

   "devDependencies": {
     ...
+    "@pivanov/vite-plugin-svg-sprite": "^3.1.3",
+    "svgo": "^4.0.0",
     "tsx": "^4.20.4",
     ...
   },
   "dependencies": {
-    "@pivanov/vite-plugin-svg-sprite": "^3.1.3",
     "@radix-ui/react-slot": "^1.2.3",
     ...
-    "svgo": "^4.0.0",
     "tailwind-merge": "^3.3.1",
     "tw-animate-css": "^1.3.7"
   }

주의: 다른 앱들의 Vite 설정에서 이 플러그인을 직접 사용한다면, 각 앱 패키지의 devDependencies에 명시돼 있어야 합니다.

Also applies to: 62-62

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1e218ed and b15d633.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • packages/design-system/package.json (2 hunks)
  • packages/design-system/vite.config.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/design-system/vite.config.ts
🔇 Additional comments (3)
packages/design-system/package.json (3)

21-21: 아이콘 통합 스크립트(icons) 추가 굿

pnpm icons:clean && pnpm generate:icons로 DX가 좋아졌습니다. 연쇄 실행 순서도 적절합니다.


48-48: tsx 추가 적절

아이콘 리스트 생성 스크립트 실행을 위한 tsx 추가가 타당합니다.


18-18: 로컬 설치된 SVGO v4에서 아래 명령들을 직접 실행해 주세요.
옵션 -f(디렉터리 지정)와 --multipass가 정상 동작하는지 확인이 필요합니다.

# SVGO 버전 확인
npx svgo --version

# help 출력에서 -f, --multipass 옵션 노출 여부 확인
npx svgo --help | grep -E " -f |--multipass"

# 실제 dry-run 테스트 (성공 시 아무 에러 없이 OK 메시지 출력)
npx svgo \
  -f packages/design-system/src/icons/source \
  --config=packages/design-system/svgo.config.mjs \
  --multipass \
  --dry-run && echo "OK"

실행 후 결과를 공유해 주시면 감사하겠습니다.

@jjangminii jjangminii merged commit 47f880b into develop Aug 21, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

setting 세팅하라 세팅

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Setting] svg sprite 세팅

3 participants