Khi phát triển ứng dụng đa nền tảng (Web và React Native) trong một monorepo, việc duy trì giao diện nhất quán là thách thức lớn. Một Design System tập trung giúp nhóm thiết kế và lập trình nói chung một ngôn ngữ, giảm thiểu sự chênh lệch về màu sắc, typography, spacing và component behavior. ## 1. Cấu trúc thư mục gợi ý - packages/design-system - src/components // các component UI thuần React (Button, Input, Card…) - src/native // wrapper cho React Native (Pressable, View, Text…) - src/theme // token màu, font, spacing, breakpoints - .storybook // cấu hình Storybook cho Web - tailwind.config.js // mở rộng theme Tailwind từ token ## 2. Định nghĩa Design Token tập trung Sử dụng file JSON hoặc TypeScript để export token, ví dụ: ```ts export const colors = { primary: { 50: '#eef2ff', 500: '#3b82f6', 900: '#1e3a8a' }, neutral: { … } }; export const spacing = { xs: 4, sm: 8, md: 16, lg: 24, xl: 32 }; ``` Token này sau đó được import vào Tailwind (theme.extend) và vào StyleSheet của React Native thông qua hàm helper. ## 3. Component chung với polymorphic props Viết component một lần, render khác nhau tùy nền tảng: ```tsx import { Platform } from 'react-native'; import { Button as WebButton } from './Button.web'; import { Button as NativeButton } from './Button.native'; export const Button = Platform.select({ web: WebButton, native: NativeButton, default: WebButton }); ``` Cách này giữ API giống nhau (variant, size, onPress) nhưng implementation tận dụng DOM hoặc native view. ## 4. Cấu hình Storybook cho cả Web và Mobile - Cài đặt `@storybook/react` và `@storybook/react-native`. - Tạo `.storybook/main.js` với `stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)']`. - Sử dụng `decorators` để bọc story trong `ThemeProvider` và `TailwindProvider`. - Chạy `npm run storybook` cho web, `npm run storybook:native` cho thiết bị/emulator. ## 5. Tích hợp Tailwind CSS - Cài `tailwindcss` và `postcss` trong package design-system. - `tailwind.config.js` import token từ `src/theme`: ```js const { colors, spacing } = require('./src/theme'); module.exports = { content: ['./src/**/*.{js,ts,jsx,tsx}'], theme: { extend: { colors, spacing } }, corePlugins: { preflight: false } }; ``` - Trong component web import `className` từ Tailwind; component native dùng `StyleSheet.create` với giá trị token. ## 6. Quy trình phát triển và review 1. Thiết kế mới component trong Figma → cập nhật token. 2. Implement component web và native song song. 3. Viết story cho mỗi variant, kiểm tra visual regression với Chromatic. 4. Publish package nội bộ (`npm publish --workspace=design-system`) hoặc dùng `changesets` để versioning. 5. Các app con chỉ cần `import { Button } from '@myorg/design-system'`. ## 7. Lời khuyên thực tế - **Token first**: không hard‑code màu hay spacing trong component. - **Polymorphic component**: giữ API thống nhất, tránh duplicate logic. - **Storybook là tài liệu sống**: bắt buộc mọi component mới phải có story. - **CI gate**: chạy lint, type‑check, test, visual regression trước khi merge. - **Versioning rõ ràng**: major cho breaking UI, minor cho component mới, patch cho fix bug. Với cách tiếp cận này, đội ngũ có thể scale giao diện nhanh chóng, đảm bảo tính nhất quán và giảm thiểu chi phí bảo trì khi mở rộng sang nền tảng mới.