Skip to content

[CHORE] SVGR 세팅 - #55

Merged
ehye1 merged 7 commits into
developfrom
chore/ui/54-setup-svgr
Jul 1, 2026
Merged

[CHORE] SVGR 세팅#55
ehye1 merged 7 commits into
developfrom
chore/ui/54-setup-svgr

Conversation

@ehye1

@ehye1 ehye1 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

ISSUE 🔗

close #54



What is this PR? 🔍

SVG Sprite 방식을 제거하고 SVGR 기반 아이콘 시스템을 구축했습니다.

왜 SVG Sprite에서 SVGR로 전환했나

SVG Sprite는 <use href> 방식으로 아이콘을 참조하는데, Next.js App Router 환경에서는 Sprite 파일을 layout에 직접 인라인 주입해야 작동합니다. 또한 아이콘을 추가할 때마다 생성 스크립트를 별도로 실행하고 iconNames.ts를 함께 관리해야 했습니다.

SVGR은 SVG를 React 컴포넌트로 직접 변환하기 때문에 일반 컴포넌트와 동일하게 named import로 사용할 수 있고, 트리쉐이킹도 자연스럽게 됩니다. Next.js 생태계에서 사실상 표준으로 자리잡은 방식이기도 합니다.

모노레포 구조에서의 설계

이 프로젝트는 timo-design-system 패키지가 아이콘을 관리하고 timo-web이 소비하는 구조입니다. 여기서 두 가지를 결정했습니다.

① 아이콘 생성은 timo-design-system 패키지에서 담당

svgr.config.mjsgenerate-icons.mjstimo-design-system에 두고, icons:generate 스크립트로 실행합니다. 생성된 컴포넌트는 @repo/timo-design-system/icons로 export됩니다.

import { PlayIcon } from '@repo/timo-design-system/icons';

② Turborepo 파이프라인으로 빌드 순서 보장

timo-webbuild 스크립트에 직접 넣지 않고 turbo.json에 별도 태스크로 등록했습니다. inputs(source SVG)와 outputs(generated 파일)를 명시해 SVG가 바뀌지 않으면 캐시를 재사용합니다. build.dependsOn: ["^icons:generate"]timo-web 빌드 전 아이콘 생성이 자동으로 선행됩니다.

프로젝트에 맞게 커스텀한 부분

항목 설정 이유
컴포넌트 네이밍 SvgPlayPlayIcon 팀 컨벤션에 맞게 템플릿에서 변환
아이콘 크기 icon: false 1em 고정 대신 CSS로 직접 제어
style 속성 제거 SVGO removeAttrs Figma export 시 P3 색상으로 인해 style이 중복 생성되어 TypeScript 에러 발생
React import 제거 jsxRuntime: 'automatic' React 17+ 자동 런타임 적용
viewBox 유지 removeViewBox: false 제거 시 CSS 크기 조절 불가



아이콘 추가 방법 📖

src/icons/source/play.svg는 동작 확인용 예시 파일입니다.

1. SVG 파일 추가

packages/timo-design-system/src/icons/source/ 폴더에 SVG 파일을 추가합니다.

src/icons/source/
├── arrow-right.svg
├── check.svg
└── play.svg     ← 예시

파일명은 소문자 kebab-case로 작성합니다. 컴포넌트 이름은 자동으로 PascalCase + Icon으로 변환됩니다.
(arrow-right.svgArrowRightIcon)

2. 아이콘 생성 실행

pnpm icons:generate

src/icons/generated/에 TSX 컴포넌트가 생성되고, src/icons/index.ts barrel이 자동 업데이트됩니다.

pnpm build 실행 시 Turborepo가 자동으로 선행 실행하므로 별도로 실행할 필요 없습니다.

3. 사용

import { ArrowRightIcon } from '@repo/timo-design-system/icons';

<ArrowRightIcon width={24} height={24} className="text-blue-500" />
  • width / height prop 또는 CSS로 크기를 지정합니다.
  • aria-hidden="true"가 기본 적용됩니다. 접근성이 필요한 경우 aria-label을 직접 추가하세요.



To Reviewers

toPascalCase-, _ 구분자 처리만 구현되어 있습니다. 파일명에 숫자나 camelCase가 들어오는 케이스는 검증하지 않았으니 아이콘 추가 시 파일명 컨벤션을 지켜주세요.



Screenshot 📷



Test Checklist ✔

  • pnpm icons:generate 실행 — PlayIcon 컴포넌트 및 barrel 정상 생성 확인
  • pnpm check-types 통과
  • pnpm build — 미실행: CI에서 확인 예정

ehye1 added 3 commits June 30, 2026 14:59
SVG를 React 컴포넌트로 변환하기 위해 @svgr/cli를 devDependency로 추가했습니다.
svgr.config.mjs에서 SVG 최적화(SVGO), JSX 자동 런타임, PlayIcon 형태의 컴포넌트 네이밍을 설정했습니다.
generate-icons.mjs는 SVGR CLI로 SVG를 TSX로 변환하고 barrel 파일을 자동 생성합니다.
turbo.json에 icons:generate 태스크를 등록해 source SVG 변경 시에만 재생성하도록 캐싱을 구성했습니다.
build가 icons:generate에 의존하도록 연결하고, generated 파일 경로를 루트 gitignore에 추가했습니다.
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
timo Ready Ready Preview, Comment Jul 1, 2026 5:35am

@github-actions github-actions Bot added the ⌚ Timo-Design-system Timo 디자인 시스템 label Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

SVGR 기반 아이콘 생성 파이프라인이 추가된다. SVG 소스는 생성 스크립트로 TSX 컴포넌트로 변환되고, 아이콘 배럴과 Turborepo 작업 의존성이 함께 갱신된다. 생성 산출물과 Storybook 로그는 Git 추적에서 제외된다.

Changes

아이콘 자동 생성 파이프라인

Layer / File(s) Summary
SVGR 설정 및 의존성 추가
packages/timo-design-system/svgr.config.mjs, packages/timo-design-system/package.json
TypeScript, 자동 JSX 런타임, SVGO 커스터마이즈, aria-hidden 기본 props, *Icon 템플릿을 정의하고, @svgr/cliicons:generate 스크립트를 추가한다.
아이콘 생성 스크립트 및 배럴 파일
packages/timo-design-system/generate-icons.mjs, packages/timo-design-system/src/icons/index.ts
generate-icons.mjssrc/icons/source SVG를 src/icons/generated로 변환하고, 생성된 파일 목록으로 index.ts 내보내기를 갱신한다.
Turborepo 및 루트 스크립트 연동
turbo.json, package.json
icons:generate 작업과 루트 실행 스크립트를 추가하고, buildcheck-types가 아이콘 생성에 선행되도록 연결한다.
생성 산출물 무시
.gitignore
build-storybook.log, src/icons/generated/, src/icons/index.ts를 Git 무시 목록에 추가한다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested labels: 🛠️ Setup

Suggested reviewers: yumin-kim2

Related issues: 54

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 직접 이슈의 핵심인 @svgr/webpack, next.config 규칙, *.svg 타입 선언이 보이지 않고 CLI 기반 생성으로 방향이 달라졌습니다. Next.js에서 SVG를 직접 import하도록 @svgr/webpack, SVG 모듈 선언, next.config 규칙, titleProp/ref 옵션을 추가하고 샘플 import를 확인하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 SVGR 세팅이라는 핵심 변경을 짧고 명확하게 잘 요약합니다.
Description check ✅ Passed 설명이 SVGR 기반 아이콘 시스템 구축과 관련되어 있어 변경 내용과 잘 맞습니다.
Out of Scope Changes check ✅ Passed 변경은 아이콘 생성과 SVGR 설정 범위에 머물러 있어 별도의 외부 작업은 보이지 않습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/ui/54-setup-svgr

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

@github-actions github-actions Bot added 🧹 CHORE 기능에 대한 임시 코드, test 코드 등 ♥️ 혜원 혜원양 labels Jun 30, 2026
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown

Storybook Preview

항목 링크
Storybook 열기
Chromatic 빌드 확인

마지막 업데이트: 2026-07-01 05:35 UTC

CI 환경에서 generated 폴더가 없어 check-types가 실패하는 문제를 수정했습니다.
@github-actions

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/ 0 B 🟡 205.30 kB
/focus 0 B 🟡 205.30 kB
/home 0 B 🟡 205.30 kB
/login 0 B 🟡 205.30 kB
/onboarding 0 B 🟡 205.30 kB
/settings 0 B 🟡 205.30 kB
/settings/account 0 B 🟡 205.30 kB
/settings/policy 0 B 🟡 205.30 kB
/statistics 0 B 🟡 205.30 kB
/today 0 B 🟡 205.30 kB

공유 번들: 205.30 kB
🟢 < 200kB  |  🟡 < 350kB  |  🔴 ≥ 350kB (First Load JS · gzip)

Lighthouse — timo-web

⚠️ Lighthouse 결과를 가져오지 못했습니다.

Image Optimization — timo-web

public/ 디렉토리에 이미지가 없습니다.

측정 커밋: eab4e3a

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/timo-design-system/generate-icons.mjs`:
- Around line 8-11: `toPascalCase()` in `generate-icons.mjs` only normalizes
hyphens and underscores, so icon filenames containing dots, spaces, or leading
digits can produce invalid export names and break the barrel file. Update the
name-generation path used for icon exports (and keep it aligned with the SVGR
template) so every filename is converted into a valid JavaScript identifier
before appending `Icon`, including sanitizing separators like `.`, whitespace,
and any non-identifier characters, and ensuring names do not start with a digit.

In `@packages/timo-design-system/svgr.config.mjs`:
- Around line 27-37: The SVGR template is generating icons as a const
declaration followed by a separate named export, which does not match the
project’s Arrow function + named export convention. Update the template in
svgr.config.mjs so the generated component uses a direct named export form (for
example, the template that builds ${name} from variables.componentName should
emit the component as an exported const), keeping the JSX and props structure
the same while removing the separate export block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0ee714e3-b5f9-468c-bcf0-9163c8be6908

📥 Commits

Reviewing files that changed from the base of the PR and between 1f4a9ec and baa7300.

⛔ Files ignored due to path filters (2)
  • packages/timo-design-system/src/icons/source/play.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • .gitignore
  • package.json
  • packages/timo-design-system/generate-icons.mjs
  • packages/timo-design-system/package.json
  • packages/timo-design-system/src/icons/index.ts
  • packages/timo-design-system/svgr.config.mjs
  • turbo.json

Comment thread packages/timo-design-system/generate-icons.mjs
Comment thread packages/timo-design-system/svgr.config.mjs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
turbo.json (2)

12-14: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

icons:generate 캐시 입력이 불완전합니다.

Line 13은 SVG 원본만 입력으로 잡고 있어서, generate-icons.mjssvgr.config.mjs가 바뀌어도 Turbo가 기존 산출물을 재사용할 수 있습니다. 그러면 생성 규칙이 바뀌었는데도 src/icons/generated/**src/icons/index.ts가 stale 상태로 남습니다. Turborepo의 task inputs 문서를 기준으로 생성 스크립트와 설정 파일도 입력에 포함해 주세요.

수정 예시
   "icons:generate": {
-    "inputs": ["src/icons/source/**"],
+    "inputs": [
+      "src/icons/source/**",
+      "generate-icons.mjs",
+      "svgr.config.mjs"
+    ],
     "outputs": ["src/icons/generated/**", "src/icons/index.ts"]
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@turbo.json` around lines 12 - 14, The `icons:generate` task in `turbo.json`
is only tracking the SVG source files, so changes to the generation logic can
leave `src/icons/generated/**` and `src/icons/index.ts` stale. Update the task’s
`inputs` to also include the icon generation script and configuration files used
by `generate-icons.mjs` and `svgr.config.mjs`, so Turbo invalidates the cache
whenever the generation rules change.

16-17: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

build도 로컬 icons:generate를 선행해야 합니다.

Line 17의 ^icons:generate는 의존 패키지의 작업만 기다립니다. 그래서 아이콘을 직접 생성하는 패키지 자체를 빌드할 때는 로컬 icons:generate가 실행되지 않아, 깨끗한 체크아웃에서 생성 파일 누락/구버전 산출물로 빌드가 흔들릴 수 있습니다. check-types처럼 build에도 로컬 의존성을 추가해 두는 편이 안전합니다. Turborepo의 dependsOn 문서를 함께 확인해 보세요.

수정 예시
   "build": {
-    "dependsOn": ["^build", "^icons:generate"],
+    "dependsOn": ["icons:generate", "^build", "^icons:generate"],
     "inputs": ["$TURBO_DEFAULT$", ".env*"],
     "outputs": [".next/**", "!.next/cache/**", "!.next/dev/**"],
     "passThroughEnv": ["SENTRY_AUTH_TOKEN"]
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@turbo.json` around lines 16 - 17, The build pipeline is only waiting on
dependency packages’ icons generation, so the package that owns `icons:generate`
can still build without first generating its local icons. Update the `build`
task in `turbo.json` so `dependsOn` includes the local `icons:generate`
dependency as well as the existing upstream one, following the same pattern used
by `check-types`, to ensure `build` always runs after `icons:generate` in the
current package.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@turbo.json`:
- Around line 12-14: The `icons:generate` task in `turbo.json` is only tracking
the SVG source files, so changes to the generation logic can leave
`src/icons/generated/**` and `src/icons/index.ts` stale. Update the task’s
`inputs` to also include the icon generation script and configuration files used
by `generate-icons.mjs` and `svgr.config.mjs`, so Turbo invalidates the cache
whenever the generation rules change.
- Around line 16-17: The build pipeline is only waiting on dependency packages’
icons generation, so the package that owns `icons:generate` can still build
without first generating its local icons. Update the `build` task in
`turbo.json` so `dependsOn` includes the local `icons:generate` dependency as
well as the existing upstream one, following the same pattern used by
`check-types`, to ensure `build` always runs after `icons:generate` in the
current package.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fcd61b80-04e5-41b2-a818-4129d3008837

📥 Commits

Reviewing files that changed from the base of the PR and between baa7300 and 92358c4.

📒 Files selected for processing (1)
  • turbo.json

named export 선언을 별도 구문으로 분리하던 방식에서 export const 인라인 방식으로 변경했습니다.

@kimminna kimminna left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

web, storybook에서 정상 임포트 & 렌더링되는 것 확인했습니다!

다만 generated/는 gitignore되어 있고 src/icons/index.ts는 커밋되는 구조인데, index.ts가 ./generated/Play를 import하므로 fresh clone 후 generated/가 없는 상태에서 타입 체크가 바로 실패합니다. IDE에서도 즉시 에러가 표시되는 문제가 있어요.

생성 파일은 커밋하지 않아야 하니까 둘 다 gitignore에 넣는 방식이 어떨까 싶어요! 터보레포가 빌드, check-types 전에 icons:generate를 항상 선행 실행하니까 워크플로우에서는 문제 없을 것 같습니다!

ehye1 added 2 commits July 1, 2026 14:28
…to chore/ui/54-setup-svgr

# Conflicts:
#	packages/timo-design-system/package.json
#	pnpm-lock.yaml
#	turbo.json
@ehye1

ehye1 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

현재 .gitignore에는 아래 두 항목만 추가했습니다.

packages/timo-design-system/src/icons/generated/ : 생성되는 아이콘 파일
packages/timo-design-system/src/icons/index.ts : 생성되는 index 파일

앞으로 icons:generate를 실행해 generated/ 아래에 파일이 추가되더라도 git에서 모두 무시되므로, SVG 원본(src/icons/source/)만 관리하면 됩니다.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
turbo.json (1)

12-15: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

icons:generate 해시 입력에 설정과 생성 스크립트를 추가하세요.
src/icons/source/**만 해시되면 svgr.config.mjsgenerate-icons.mjs를 바꿔도 캐시가 그대로 재사용될 수 있어요. 아이콘 파이프라인은 깔끔한데, 캐시 재료가 조금 부족합니다 🙂

🔧 제안
     "icons:generate": {
-      "inputs": ["src/icons/source/**"],
+      "inputs": ["src/icons/source/**", "svgr.config.mjs", "generate-icons.mjs"],
       "outputs": ["src/icons/generated/**", "src/icons/index.ts"]
     },

Turborepo의 inputs는 태스크 해시에 포함할 파일을 지정하므로, 관련 설정/스크립트도 함께 넣는 게 맞아요. https://turborepo.dev/docs/reference/configuration#inputs

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@turbo.json` around lines 12 - 15, `icons:generate` 태스크의 해시 입력이
`src/icons/source/**`만 포함해서 `svgr.config.mjs`와 `generate-icons.mjs` 변경이 캐시에 반영되지
않습니다. `turbo.json`의 `icons:generate` 설정에서 이 두 파일도 `inputs`에 포함되도록 추가해, 아이콘 생성
결과가 설정/스크립트 변경에 따라 다시 실행되게 수정하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@turbo.json`:
- Around line 12-15: `icons:generate` 태스크의 해시 입력이 `src/icons/source/**`만 포함해서
`svgr.config.mjs`와 `generate-icons.mjs` 변경이 캐시에 반영되지 않습니다. `turbo.json`의
`icons:generate` 설정에서 이 두 파일도 `inputs`에 포함되도록 추가해, 아이콘 생성 결과가 설정/스크립트 변경에 따라 다시
실행되게 수정하세요.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 083c7ea0-ee82-4815-9d98-a2bd00305acf

📥 Commits

Reviewing files that changed from the base of the PR and between 47cc83d and 6f59da0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • .gitignore
  • package.json
  • packages/timo-design-system/package.json
  • packages/timo-design-system/src/icons/index.ts
  • turbo.json
💤 Files with no reviewable changes (1)
  • packages/timo-design-system/src/icons/index.ts

@kimminna kimminna left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

너무 좋습니다~~!

@jjangminii jjangminii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SVG Sprite에서 SVGR로 전환하느라 고생했어요-!
inputs/outputs 명시로 SVG가 바뀌지 않으면 캐시를 재사용하는 부분도 꼼꼼하게 챙겨주셨네요 👍
감사합니다~~

@yumin-kim2 yumin-kim2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

처음 보는 개념들인데 PR 설명 덕분에 흐름을 잘 이해할 수 있었어요 🙏 SVG 넣고 명령어 하나로 끝나는 구조 너무 편리할 것 같아요.! 너무 수고하셨습니당 ~~~👍👍

Comment thread turbo.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

dependsOn으로 아이콘 생성 → 빌드 순서를 보장할 수 있다는게 신기하네요..!
SVG 바뀔 때만 다시 생성하고 캐시 쓰는 것도 더 효율적으로 쓸 수 있는 것 같아요. 많이 배워갑니다 🫰🏻

Comment on lines +10 to +11
.replace(/[-_](.)/g, (_, c) => c.toUpperCase())
.replace(/^(.)/, (_, c) => c.toUpperCase());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

처음 보는 패턴이 있어서 찾아봤더니 정규식이라는 걸 처음 알게 됐어요! 복잡한 문자열 변환을 한 줄로 처리할 수 있는게 신기하네요 👀

@ehye1
ehye1 merged commit 680719d into develop Jul 1, 2026
18 checks passed
@kimminna
kimminna deleted the chore/ui/54-setup-svgr branch July 1, 2026 10:52
@kimminna kimminna mentioned this pull request Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⌚ Timo-Design-system Timo 디자인 시스템 ♥️ 혜원 혜원양 🧹 CHORE 기능에 대한 임시 코드, test 코드 등

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CHORE] SVGR 세팅

4 participants