Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"react-dom": "^19.1.1"
},
"devDependencies": {
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@eslint/js": "^9.33.0",
"@pinback/eslint-config": "workspace:*",
"@pinback/typescript-config": "workspace:*",
Expand Down
12 changes: 11 additions & 1 deletion apps/client/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import svgSpritePlugin from '@pivanov/vite-plugin-svg-sprite';

// https://vite.dev/config/
export default defineConfig({
// TODO: svg 설정 추가
plugins: [react(), tsconfigPaths(), tailwindcss()],
plugins: [
react(),
tsconfigPaths(),
tailwindcss(),
svgSpritePlugin({
iconDirs: ['../../packages/design-system/src/icons/source'],
symbolId: 'icon-[name]',
inject: 'body-last',
}),
],
});
2 changes: 1 addition & 1 deletion apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
"zip": "vite build && node scripts/zip.mjs"
},
"dependencies": {
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@tanstack/react-query": "^5.85.3",
"react": "^19.1.1",
"react-dom": "^19.1.1"
},
"devDependencies": {
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@crxjs/vite-plugin": "^2.2.0",
"@eslint/js": "^9.33.0",
"@pinback/design-system": "workspace:*",
Expand Down
12 changes: 9 additions & 3 deletions apps/extension/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,26 @@ import tsconfigPaths from 'vite-tsconfig-paths';
import { resolve } from 'path';
import { crx } from '@crxjs/vite-plugin';
import manifest from './manifest.json';
import svgSpritePlugin from '@pivanov/vite-plugin-svg-sprite';

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

build: {
outDir: 'dist',
copyPublicDir: true,

},
publicDir: 'public',
resolve: {
Expand All @@ -32,4 +38,4 @@ export default defineConfig({
'@components': resolve(__dirname, './src/components'),
},
},
});
});
1 change: 1 addition & 0 deletions apps/landing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"react-dom": "^19.1.1"
},
"devDependencies": {
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@eslint/js": "^9.33.0",
"@pinback/eslint-config": "workspace:*",
"@pinback/typescript-config": "workspace:*",
Expand Down
12 changes: 11 additions & 1 deletion apps/landing/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import svgSpritePlugin from '@pivanov/vite-plugin-svg-sprite';

// https://vite.dev/config/
export default defineConfig({
// TODO: svg 설정 추가
plugins: [react(), tsconfigPaths(), tailwindcss()],
plugins: [
react(),
tsconfigPaths(),
tailwindcss(),
svgSpritePlugin({
iconDirs: ['../../packages/design-system/src/icons/source'],
symbolId: 'icon-[name]',
inject: 'body-last',
}),
],
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"test": "turbo run test"
},
"devDependencies": {
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"prettier": "^3.6.2",
"prettier-plugin-tailwindcss": "^0.6.14",
Expand All @@ -27,4 +28,3 @@
"node": ">=18"
}
}

8 changes: 7 additions & 1 deletion packages/design-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
"build": "vite build",
"build:storybook": "storybook build",
"dev:storybook": "storybook dev -p 6006",
"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",
Comment on lines +18 to +19
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.

Copy link
Member

Choose a reason for hiding this comment

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

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

"generate:component": "turbo gen react-component",
"icons": "pnpm icons:clean && pnpm generate:icons"
},
"devDependencies": {
"@chromatic-com/storybook": "4.1.1",
Expand All @@ -42,18 +45,21 @@
"playwright": "^1.55.0",
"storybook": "9.1.3",
"tailwindcss": "^4.1.12",
"tsx": "^4.20.4",
"typescript": "5.9.2",
"typescript-eslint": "^8.39.1",
"vite": "^7.1.2",
"vitest": "^3.2.4"
},
"dependencies": {
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.540.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"svgo": "^4.0.0",
"tailwind-merge": "^3.3.1",
"tw-animate-css": "^1.3.7"
}
Expand Down
106 changes: 106 additions & 0 deletions packages/design-system/src/icons/components/icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
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.

import React from 'react';
import clsx from 'clsx';

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.

와우..고생하셨습니다!

| 'main0'
| 'main100'
| 'main200'
| 'main300'
| 'main400'
| 'main500'
| 'main600'
| 'gradient-start'
| 'gradient-end'
| 'secondary'
| 'gray0'
| 'gray100'
| 'gray200'
| 'gray300'
| 'gray400'
| 'gray500'
| 'gray600'
| 'gray700'
| 'gray800'
| 'gray900'
| 'white-bg'
| 'gray-bg'
| 'font-black-1'
| 'font-gray-2'
| 'font-gray-3'
| 'font-ltgray-4'
| 'font-ltgray-5'
| 'error'
| 'success'
| 'category-red-text'
| 'category-purple-text'
| 'category-navyblue-text'
| 'category-skyblue-text'
| 'category-emerald-text'
| 'category-navygreen-text'
| 'category-khaki-text'
| 'category-orange-text'
| 'category-amber-text'
| 'category-maroon-text'
| 'category-red-bg'
| 'category-purple-bg'
| 'category-navyblue-bg'
| 'category-skyblue-bg'
| 'category-emerald-bg'
| 'category-navygreen-bg'
| 'category-khaki-bg'
| 'category-orange-bg'
| 'category-amber-bg'
| 'category-maroon-bg';

interface IconProps extends React.SVGProps<SVGSVGElement> {
name: IconName;
size?: number | string;
width?: number | string;
height?: number | string;
color?: IconColor;
className?: string;
rotate?: IconRotate;
ariaHidden?: boolean;
}

export const Icon = ({
name,
size,
width,
height,
color,
className,
rotate,
ariaHidden = true,
...rest
}: IconProps) => {
const w = width ?? size ?? 20;
const h = height ?? size ?? 20;
Comment on lines +80 to +81
Copy link
Member

Choose a reason for hiding this comment

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

fallback까지 굳굳 👍


const rotateClass =
rotate === 90
? 'rotate-90'
: rotate === 180
? 'rotate-180'
: rotate === 270
? 'rotate-[270deg]'
: '';

const combined = clsx('inline-block', rotateClass, className);

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}
{...rest}
>
<use href={`#icon-${name}`} />
</svg>
Comment on lines +103 to +104
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.

);
};
15 changes: 15 additions & 0 deletions packages/design-system/src/icons/iconNames.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 이 파일은 자동 생성 파일입니다. (직접 수정 금지)
export const iconNames = [
'ic_arrow_down_active',
'ic_arrow_down_disable',
'ic_bookmark_active',
'ic_bookmark_disable',
'ic_clock_active',
'ic_clock_disable',
'ic_close',
'ic_details_category',
'ic_details_disable',
'ic_info',
'ic_plus',
] as const;
export type IconName = (typeof iconNames)[number];
1 change: 1 addition & 0 deletions packages/design-system/src/icons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Icon } from './components/icon';
20 changes: 20 additions & 0 deletions packages/design-system/src/icons/scripts/generate-icon-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { readdirSync, writeFileSync } from 'fs';
import { basename, dirname, join } from 'path';
import { fileURLToPath } from 'url';

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

const ICON_DIR = join(__dirname, '../source');
const OUTPUT_PATH = join(__dirname, '../iconNames.ts');

const files = readdirSync(ICON_DIR).filter((file) => file.endsWith('.svg'));

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파일에 자동생성됩니당

export const iconNames = ${JSON.stringify(iconNames)} as const;
export type IconName = typeof iconNames[number];
`;

writeFileSync(OUTPUT_PATH, content);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/design-system/src/icons/source/ic_close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/design-system/src/icons/source/ic_info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/design-system/src/icons/source/ic_plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions packages/design-system/svgo.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default {
multipass: true,
plugins: [
// 기본 최적화 + viewBox 유지
{ name: 'preset-default', params: { overrides: { removeViewBox: false } } },
// 루트 <svg>의 width/height 제거
{ name: 'removeDimensions' },
],
};
2 changes: 2 additions & 0 deletions packages/design-system/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"extends": "@pinback/typescript-config/react.json",
"compilerOptions": {
"typeRoots": ["node_modules/@types"],

"outDir": "dist",
"baseUrl": ".",
"paths": {
Expand Down
11 changes: 10 additions & 1 deletion packages/design-system/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import svgSpritePlugin from '@pivanov/vite-plugin-svg-sprite';
/// <reference types="vitest/config" />
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
Expand All @@ -12,7 +13,15 @@ const dirname =

// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
export default defineConfig({
plugins: [react(), tailwindcss()],
plugins: [
react(),
tailwindcss(),
svgSpritePlugin({
iconDirs: ['src/icons/source'],
symbolId: 'icon-[name]',
inject: 'body-last',
}),
],
Comment on lines +16 to +24
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 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.

resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
Expand Down
Loading
Loading