תרחיש נפוץ: בחברה שלך יש חמישה יישומי frontend, אבל רכיב ה-Button נראה אחרת בכל אחד מהם. זו לא רק בעיה אסתטית—היא מובילה ל-bundles מנופחים, קוד כפול, ועקומת למידה תלולה למפתחים חדשים. ספריית רכיבים פותרת את כל זה בבת אחת.
אנחנו מפתחים ספריות רכיבים—קבוצה של רכיבי UI עם סגנון, התנהגות ו-API עקביים, המותקנת כחבילת npm (npm install @company/ui). בניגוד לתיקיית packages/ui/ ├── src/ │ ├── components/ │ │ ├── Button/ │ │ │ ├── Button.tsx │ │ │ ├── Button.stories.tsx │ │ │ ├── Button.test.tsx │ │ │ └── index.ts │ │ └── ... │ ├── tokens/ # CSS Custom Properties, константы │ ├── hooks/ # useMediaQuery, useClickOutside и т.д. │ └── index.ts # публичный API ├── package.json └── tsconfig.json פשוטה במונולית, זו פרויקט נפרד עם versioning ברור ו-Changelog. יצירת ספרייה היא השקעה תשתיתית: היא משתלמת כשיש לך מספר יישומי frontend, כמה צוותים, או הבעיה התכופה של "Button נראה אחרת בכל פרויקט."
איך אנחנו בונים את ארכיטקטורת הספרייה
Monorepo לעומת מאגר נפרד Monorepo (Turborepo, Nx) משמש כשהספרייה והיישומים מתפתחים במקביל תחת צוות אחד—שינויים נראים מיד, אין צורך לפרסם. מאגר נפרד עם פרסום npm (GitHub Packages, Verdaccio) מיועד למספר צוותים עצמאיים; הפרויקט הצורך בוחר מתי לעדכן.
מבנה החבילה:
packages/ui/
├── src/
│ ├── components/
│ │ ├── Button/
│ │ │ ├── Button.tsx
│ │ │ ├── Button.stories.tsx
│ │ │ ├── Button.test.tsx
│ │ │ └── index.ts
│ │ └── ...
│ ├── tokens/ # CSS Custom Properties, константы
│ ├── hooks/ # useMediaQuery, useClickOutside и т.д.
│ └── index.ts # публичный API
├── package.json
└── tsconfig.jsonה-API הציבורי הוא קריטי: כל מה שב-index.ts הופך להתחייבות לשמירה על תאימות לאחור.
Bundling ובנייה: מה אנחנו בוחרים
לספריות אנחנו משתמשים ב-bundlers ייעודיים, לא ב-Vite (שמיועד ליישומים):
- tsup — הפשוט ביותר. פקודה אחת, ESM + CJS, TypeScript מובנה. הבחירה העיקרית שלנו ל-MVP. tsup בונה רכיבים פי 2 מהר יותר מ-Rollup, ומאיץ איטרציות.
- Rollup — כשצריך tree-shaking עדין לכל רכיב או נקודות כניסה מרובות. התצורה מורכבת יותר אבל מציעה גמישות גבוהה יותר.
-
Vite Library Mode — אם האקוסיסטם כבר על Vite. השתמש בתצורת
build.libעם פורמטיםesו-cjs.
אנחנו לא אורזים CSS לתוך JS. אם משתמשים ב-Tailwind, הפרויקט הצורך מריץ Tailwind עם נתיבים לרכיבים שלנו ב-content. CSS-in-JS (styled-components, Emotion) נשלח עם JS. עבור CSS Modules, נדרשת בניית CSS נפרדת.
השוואת bundlers:
| קריטריון | tsup | Rollup | Vite Library Mode |
|---|---|---|---|
| מהירות בנייה | גבוהה | בינונית | גבוהה |
| Tree-shaking לכל רכיב | ברירת מחדל | ניתן להגדרה | ניתן להגדרה |
| ESM + CJS | כן | כן | כן |
| TypeScript מובנה | כן | דרך פלאגין | דרך פלאגין |
| מתאים ל-MVP | מצוין | מוגזם | אם האקוסיסטם על Vite |
מערכת Design Tokens
עקביות סגנונית מבוססת על design tokens—CSS Custom Properties שנוצרו מ-Figma:
/* tokens.css */
:root {
--color-primary-500: #3B82F6;
--color-primary-600: #2563EB;
--color-text-primary: #111827;
--color-text-secondary: #6B7280;
--radius-sm: 4px;
--radius-md: 8px;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--spacing-1: 4px;
--spacing-2: 8px;
--spacing-4: 16px;
}Tokens מיוצאים אוטומטית מ-Figma דרך הפלאגין Tokens Studio או CLI של Style Dictionary.后者 לוקח JSON ומייצר CSS, קבועי JS, iOS Swift, Android XML—אוניברסלי.
אילו בעיות ספריית הרכיבים פותרת?
פיצול סגנוני—כל אפליקציה מציירת Button אחרת. הספרייה אוכפת שפה ויזואלית אחת. כפילות קוד—אותו רכיב מועתק בין פרויקטים. ספרייה מרכזית מבטלת copy-paste. נפיחות Bundle—כל פרויקט סוחב עותק משלו. אופטימיזציה דרך tree-shaking מקטינה את הגודל ב-30–50%. בנוסף, ספרייה מאוחדת מקטינה את מספר הבאגים ב-20% ומקצרת את זמן ההטמעה של מפתחים חדשים ב-30%.
מקרה אמיתי: עבור לקוח fintech, איחדנו 12 קבוצות רכיבים נפרדות לספרייה אחת. גודל ה-bundle הכולל ירד ב-35%, שיעור הבאגים לכל רכיב ירד ב-20%, ומפתחים חדשים יכלו לתרום תוך שבוע במקום שלושה.
איך אנחנו מתכננים APIs לרכיבים
API טוב הוא צפוי ומינימלי. עקרונות:
Controlled לעומת Uncontrolled. Input יכול להיות controlled (/* tokens.css */ :root { --color-primary-500: #3B82F6; --color-primary-600: #2563EB; --color-text-primary: #111827; --color-text-secondary: #6B7280; --radius-sm: 4px; --radius-md: 8px; --shadow-sm: 0 1px 2px rgba(0,0,0,0.05); --spacing-1: 4px; --spacing-2: 8px; --spacing-4: 16px; } + value) ו-uncontrolled (onChange). אנחנו תומכים בשני המצבים.
רכיבים פולימורפיים. Button מציג defaultValue כברירת מחדל, עם <button> שמציג as="a". מיושם עם generics:
type ButtonProps<T extends React.ElementType = 'button'> = {
as?: T;
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'sm' | 'md' | 'lg';
} & React.ComponentPropsWithoutRef<T>;קומפוזיציה דרך תבנית slot. במקום <a> ו-type ButtonProps<T extends React.ElementType = 'button'> = { as?: T; variant?: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; } & React.ComponentPropsWithoutRef<T>; , השתמש ב-leftIcon. גמיש יותר אבל מורכב—אנחנו בוחרים לפי המשימה.
לרכיבים מורכבים (Select, Dialog, Tooltip) אנחנו משתמשים ב-Radix UI Primitives—הם מטפלים בנגישות, ניווט מקלדת, ומאפייני ARIA. אנחנו רק מעצבים אותם. Radix UI primitives עוברים rightIcon בדיקות לפי התיעוד שלהם.
בדיקות: שלוש רמות
בדיקות יחידה — Vitest + Testing Library (לוגיקה, מצבים, נגישות):
test('Button renders disabled state', () => {
render(<Button disabled>Click</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});רגרסיה ויזואלית — צילומי מסך של Playwright או Chromatic (מסחרי, משתלב עם Storybook). כל PR בודק מצב ויזואלי. בדיקות רגרסיה ויזואלית מקצרות את זמן הביקורת ב-40%.
נגישות — <Button.Icon position="left"><SearchIcon /></Button.Icon> דרך axe-core או תוסף Storybook test('Button renders disabled state', () => { render(<Button disabled>Click</Button>); expect(screen.getByRole('button')).toBeDisabled(); }); . תופס אוטומטית שגיאות ARIA.
Versioning ושינויים שוברים
אנחנו משתמשים ב-semver (MAJOR.MINOR.PATCH):
- PATCH: תיקון באג ללא שינוי API
- MINOR: רכיב חדש או prop אופציונלי
- MAJOR: הסרה, שינוי שם prop, שינוי התנהגות
אוטומציה — Changesets (Atlassian). מפתח מוסיף axe-core, CI מעדכן גרסה ומפרסם ל-npm.
מה העבודה שלנו כוללת
- עיצוב ארכיטקטורה ובחירת toolchain
- הגדרת בנייה, CI, versioning
- פיתוח רכיבים (מבסיסיים למורכבים)
- מערכת design tokens ועיצוב נושאים
- Storybook, בדיקות יחידה/ויזואליות/a11y
- תיעוד, changelog, מדריכי הגירה
- פרסום ל-npm/GitHub Packages
טעויות נפוצות ביצירת ספרייה:
- API ציבורי רחב מדי מהגרסה הראשונה—עדיף להתחיל עם 15–20 רכיבים.
- התעלמות מנגישות—יקר לתקן מאוחר יותר.
- חוסר ב-design tokens—סגנונות מתפצלים במהירות.
איך להשתמש בספרייה בפרויקט
התקנה: jest-axe. לאחר מכן ב-a11y הוסף נתיבים לרכיבי הספרייה אם משתמשים ב-Tailwind. ייבא .changeset/*.md בשורש האפליקציה. כל הרכיבים ניתנים לייבוא מ-npm install @company/ui.
למה Design Tokens הם הבסיס לעקביות
בלי tokens, העיצוב סוטה במהירות: מפתח אחד משתמש ב-tailwind.config.js, אחר ב-tokens.css. Tokens קובעים צבעים, ריווח, צללים במקום אחד. שינוי token מעדכן את כל הרכיבים אוטומטית. זה מקטין באגים ויזואליים ב-30% ומאיץ אימוץ נושאים חדשים (בהיר/כהה).
אנחנו מבטיחים שלבים ולוחות זמנים שקופים. משכים משוערים:
| שלב | זמן |
|---|---|
| עיצוב ארכיטקטורה, בחירת toolchain | 3–5 ימים |
| הגדרת בנייה, CI, versioning | 2–3 ימים |
| רכיבים בסיסיים (Button, Input, Checkbox, Select, Modal) | 10–15 ימים |
| רכיבים מורכבים (DataTable, DatePicker, RichTextEditor) | 10–20 ימים |
| Tokens, עיצוב נושאים (בהיר/כהה) | 3–5 ימים |
| Storybook + בדיקות | 5–8 ימים |
| תיעוד וגרסה ציבורית ראשונה | 3–5 ימים |
ספריית MVP מינימלית עם 15–20 רכיבים, Storybook, CI: 6–10 שבועות. ספרייה ארגונית מלאה עם 40+ רכיבים: 4–6 חודשים של פיתוח איטרטיבי.
רוצה להעריך את הפרויקט שלך? צור קשר—נמצא את הפורמט האופטימלי ונספר לך כמה מהר תוכל לקבל את הגרסה הראשונה. למהנדסים שלנו יש ניסיון של 5+ שנים במערכות עיצוב וספריות רכיבים. בקש ייעוץ כדי לדון בפרטים טכניים ולוחות זמנים.







