React: مكتبة مكونات واجهة المستخدم
آخر تحديث: 2026-08-26
بدأ توم من الصفر في تصميم لوحة الإدارة الخاصة بمدونته. وبعد ستة أشهر، أصبح الكود مليئًا بأنماط
style={{}}المضمنة المتكررة وأسماء فئات CSS المكتوبة يدويًّا. كان تطوير الميزات الجديدة يتباطأ، وكانت أنماط واجهة المستخدم غير متسقة عبر الصفحات المختلفة. كان يعلم أن الوقت قد حان لاعتماد مكتبة مكونات واجهة مستخدم احترافية، لكنه واجه العديد من الخيارات — مثل Ant Design وMaterial UI وHeadless UI — فوجد توم نفسه في حيرة من أمره.
1. ما ستتعلمه
- فلسفات التصميم ومعايير الاختيار لثلاث مكتبات رئيسية لمكونات واجهة المستخدم (Ant Design / Material UI / Headless UI)
- تهيئة Ant Design، وتخصيص السمات، والتدويل
- حل تخصيص للمكونات غير المصممة باستخدام واجهة المستخدم «Headless UI» و«Tailwind CSS»
- التحميل حسب الطلب لمكتبات المكونات وعملية «ترجيد الشجرة» (Tree Shaking) لتحسين الأداء
- أفضل طريقة لدمج مكتبة المكونات مع Next.js (الاستيراد الديناميكي، حدود مكونات العميل)
- حلول تخصيص السمات وتكوين التدويل (ConfigProvider، ThemeProvider)
- تحسين أداء مكتبة المكونات: الاستيراد الديناميكي، تقنية «تري شيكينغ»، optimizePackageImports
- الاستراتيجيات وإدارة الحدود عند دمج مكتبات مكونات متعددة
2. المخططات المفاهيمية
أوجز توم عملية اتخاذ القرار المتعلقة باختيار مكتبة مكونات واجهة المستخدم: استنادًا إلى ثلاثة عوامل — نوع المشروع، وخلفية الفريق، واحتياجات التخصيص — اختار الحل الأنسب من بين مكتبات المكونات. وتتميز الأنواع المختلفة من مكتبات المكونات بمزاياها وقيودها الخاصة في السيناريوهات المختلفة.
تتفرع شجرة القرار أولاً حسب نوع المشروع: فمشاريع «الخلفية» و«الطبقة الوسطى» تعطي الأولوية لاكتمال المكونات، بينما تعطي مشاريع «الواجهة الأمامية» الأولوية للتأثيرات البصرية وإرشادات التصميم. تؤثر خلفية الفريق بشكل مباشر على منحنى التعلم وكفاءة التطوير: تتأقلم فرق React مع Ant Design بشكل أسرع، بينما تجد الفرق التي تركز على التصميم أن استخدام Material UI جنبًا إلى جنب مع إرشادات تصميم Figma أكثر سلاسة. وتتمثل نقطة القرار النهائية في التحميل حسب الطلب وتحسين الأداء — بغض النظر عن المكتبة المختارة، يجب إعداد التكوين المناسب للتحميل حسب الطلب عند دمجها في Next.js.
flowchart TD
A[Select UI Component Library] --> B{Project Type?}
B -->|Backend Management/Enterprise Applications| C[Ant Design<br/>Comprehensive enterprise-level components]
B -->|Consumer-Facing Front End| D[Material UI<br/>Modern Visual Style]
B -->|Highly Customized Requirements| E[Headless UI<br/>No style + Customizable]
C --> F{Team Background?}
D --> F
E --> F
F -->|React Team| G[Ant Design<br/>React Best Ecology]
F -->|Designer-led| H[Material UI<br/>Mature design specifications]
F -->|Fully Customizable Design| I[Headless UI<br/>Full Control Over Styles]
G --> J[Integrated into Next.js]
H --> J
I --> J
J --> K[Load on Demand Tree Shaking]
K --> L[Theme Customization]
L --> M[Performance Optimization]
3. سيناريو واقعي
تم تصميم لوحة التحكم الإدارية الخاصة بـ«توم» في البداية يدويًّا بالكامل. وبعد ستة أشهر، توسع المشروع ليشمل أكثر من 30 صفحة، لكل منها ملف CSS خاص بها. كانت أنماط الأزرار غير متسقة، وافتقرت مكونات الجداول إلى الوظائف المطلوبة، كما أنه قام بتنفيذ أداة اختيار التاريخ من الصفر ثلاث مرات. وقضى أسبوعًا في البحث عن مكتبات مكونات واجهة المستخدم الشائعة.
في النهاية، اختار توم Ant Design لثلاثة أسباب: أولاً، يقدم Ant Design المجموعة الأكثر شمولاً من المكونات — فالمكونات المخصصة للمؤسسات، مثل الجداول والنماذج وأدوات اختيار التاريخ، جاهزة للاستخدام فورًا دون الحاجة إلى إعدادات إضافية؛ ثانيًا، يدعم التحميل حسب الطلب و«تصفية الشجرة» (tree shaking)، وبالتالي لا يؤدي إلى تضخم حجم المشروع؛ ثالثًا، التكامل مع Next.js راسخ بالفعل، ويحتوي المجتمع على ثروة من الأمثلة العملية. كما استخدم «Headless UI» لتخصيص بعض المكونات الخاصة غير المتوفرة في Ant Design.
تعتبر عملية الاختيار التي اتبعها توم مفيدة للغاية: فقد أمضى أولاً أسبوعاً في دمج ثلاث مكتبات في مشروع تجريبي، وقام بتقييمها بناءً على ثلاثة معايير، وهي: كفاءة التطوير، وتأثير الأداء، ومنحنى التعلم. وتصدرت Ant Design الترتيب في جميع المجالات في سيناريو الخلفية المؤسسية. ويمكن أيضاً تطبيق نهج «الاختبار أولاً، ثم اتخاذ القرار» هذا على عملية اختيار المشاريع الخاصة بك.
(1) مقارنة بين خيارات مكتبات المكونات
| للمقارنة | Ant Design | Material UI | واجهة المستخدم بدون واجهة |
|---|---|---|---|
| لغة التصميم | البنية الخلفية على مستوى المؤسسة | تصميم Google Material | بدون أنماط (منطق السلوك) |
| عدد المكونات | 60+ | 50+ | ~15 |
| تخصيص السمة | ConfigProvider + الرمز المميز | ThemeProvider + خاصية sx | قابل للتخصيص بالكامل (Tailwind/CSS) |
| خيارات التصميم | CSS-in-JS (الإصدار 5) | CSS-in-JS (Emotion) | بدون أنماط مدمجة |
| الترجمة إلى اللغات المختلفة | أكثر من 50 لغة مدمجة | أكثر من 30 لغة مدمجة | لا توجد لغات مدمجة |
| حالات الاستخدام | إدارة الخلفية، تطبيقات المؤسسات | التطبيقات الموجهة للمستهلكين | المشاريع عالية التخصيص |
| هز الشجرة | ✅ تلقائي | ✅ تلقائي | ✅ تلقائي |
| منحنى التعلم | متوسط | متوسط | منخفض (يتطلب تصميمًا مخصصًا) |
عند اختيار مكتبة مكونات واجهة المستخدم، يجب أن تضع في اعتبارك ثلاثة عوامل رئيسية: شمولية المكونات (ما إذا كانت تغطي احتياجات عملك)، ومرونة التخصيص (ما إذا كانت تلبي متطلبات المصممين)، وتأثيرها على الأداء (ما إذا كانت تبطئ عملية تحميل الشاشة الأولى).
Ant Design (antd) is the most popular React UI library in China, open-sourced by Ant Financial. Its design language is geared toward enterprise-level back-end and middle-tier applications, providing a full suite of components ranging from buttons and tables to date pickers and tree controls. The interaction logic between components has been extensively tested, making them ready for use in complex scenarios—such as pagination, sorting, and filter synchronization in data tables.
Material UI (MUI) is a React implementation of Google’s Material Design guidelines. Its strengths lie in its mature design guidelines, modern visual style, and robust theme system. It is well-suited for consumer-facing front-end applications and designer-led teams.
Headless UI differs from the two categories above—it does not provide any predefined styles, but only provides behavioral logic (accessibility, keyboard navigation, focus management). Developers are entirely responsible for implementing the styling themselves using Tailwind CSS or CSS Modules. It is suitable for projects that require a highly customized visual style.
▶ المثال 1: مقارنة بين طرق تنفيذ الأزرار عبر مكتبات المكونات
// === Ant Design button ===
// Ready to Use Out of the Box,Built-in Styles,Through type Switch Visual Styles by Attribute
import { Button, Space } from 'antd'
function AntDButtons() {
return (
<Space wrap>
<Button type="primary">Main Buttons</Button>
<Button>Default Button</Button>
<Button type="dashed">Dotted-line button</Button>
<Button type="link">Link Button</Button>
<Button type="primary" danger>Danger Button</Button>
<Button loading>Loading...</Button>
<Button type="primary" icon={<SearchOutlined />}>Search</Button>
</Space>
)
}
// === Material UI Button ===
// Through variant and color Combining Properties to Achieve Different Styles
import Button from '@mui/material/Button'
import Stack from '@mui/material/Stack'
import SaveIcon from '@mui/icons-material/Save'
function MUIButtons() {
return (
<Stack direction="row" spacing={2}>
<Button variant="contained">Fill Button</Button>
<Button variant="outlined">Outline Button</Button>
<Button variant="text">Text Button</Button>
<Button variant="contained" color="error">Danger</Button>
<Button variant="contained" disabled>Disable</Button>
<Button variant="contained" startIcon={<SaveIcon />}>Save</Button>
</Stack>
)
}
// === Headless UI + Tailwind ===
// Unstyled Components + Custom Class
import { Button as HeadlessButton } from '@headlessui/react'
function HeadlessButtons() {
return (
<div className="flex gap-2">
<HeadlessButton className="rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-500 data-[active]:bg-blue-700">
Main Buttons
</HeadlessButton>
<HeadlessButton className="rounded border border-gray-300 px-4 py-2 text-gray-700 hover:bg-gray-50">
Default Button
</HeadlessButton>
<HeadlessButton className="rounded bg-red-600 px-4 py-2 text-white hover:bg-red-500">
Danger Button
</HeadlessButton>
</div>
)
}
(2) دمج Ant Design مع Next.js
عند دمج Ant Design في Next.js، يجب معالجة عدة مشكلات رئيسية: التوافق مع نهج CSS-in-JS، والتحميل حسب الطلب، وحدود المكونات على جانب العميل. يستخدم Ant Design v5 نهج CSS-in-JS (cssinjs)، الأمر الذي يتطلب إجراء بعض الإعدادات في Next.js لضمان إدراج الأنماط بشكل صحيح.
| مشكلات التكامل | السبب | الحل |
|---|---|---|
| توافق CSS-in-JS مع SSR | لا يمكن إدراج أنماط CSS-in-JS على جانب الخادم | تغليف حدود مكونات العميل باستخدام AntdProvider |
| حجم الشاشة الأولى كبير جدًا | مكتبة antd بأكملها مدمجة في ملف JS الأولي | dynamic() الاستيراد الديناميكي + optimizePackageImports |
| خطأ في مكون الخادم | تعتمد مكونات antd على واجهات برمجة تطبيقات المتصفح | أضف 'use client' في أعلى الملف الذي يستخدم المكون |
| وميض المحتوى غير المنسق (FOUC) | عدم وجود أنماط من جانب الخادم؛ وإدراج متأخر من جانب العميل | استخراج ملفات CSS الأساسية أو استخدام المكون App للإدارة المركزية |
| وميض عند تبديل السمة | يتم تحميل رمز السمة على جانب العميل فقط | تعيين السمة الافتراضية في ConfigProvider وإدراجها عبر SSR |
لتحسين الأداء، ينبغي أن تستخدم المكونات الاستيراد الديناميكي (dynamic) للتحميل حسب الحاجة، وذلك لتجنب تضمين مكتبة المكونات بالكامل في كود جافا سكريبت الموجود في الجزء المرئي من الصفحة. تعمل ميزة «Tree Shaking» في Ant Design تلقائيًا عند البناء باستخدام ES Modules — ما عليك سوى الاستيراد مباشرةً من antd؛ ولا يلزم إجراء أي تكوين لـ babel-plugin-import.
▶ المثال 2: التكامل الكامل بين Ant Design وNext.js
// app/providers.tsx - Ant Design Themes and Configuration Provider
'use client'
import { useState } from 'react'
import { ConfigProvider, theme, App } from 'antd'
import zhCN from 'antd/locale/zh_CN'
export function AntdProvider({ children }: { children: React.ReactNode }) {
const [isDark] = useState(false)
return (
<ConfigProvider
locale={zhCN}
theme={{
// Switch to Light Mode/Dark Theme
algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm,
// Custom Theme Colors
token: {
colorPrimary: '#1677ff',
borderRadius: 6,
colorBgContainer: isDark ? '#141414' : '#ffffff',
},
}}
>
<App>{children}</App>
</ConfigProvider>
)
}
// app/layout.tsx - Global Import AntdProvider
import { AntdProvider } from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="zh">
<body>
<AntdProvider>{children}</AntdProvider>
</body>
</html>
)
}
// app/dashboard/page.tsx - Use dynamic import to load on demand Ant Design Components
// Avoid putting the entire antd Pack into the first screen JS in
import dynamic from 'next/dynamic'
// Dynamic Import(Load only when needed)
const DataTable = dynamic(() => import('@/components/DataTable'), {
loading: () => <div>Loading the table......</div>,
})
const DatePicker = dynamic(() => import('antd').then(mod => mod.DatePicker), {
loading: () => <div>Loading the date picker......</div>,
})
async function DashboardPage() {
// Analog Data Acquisition
const data = await fetch('https://api.example.com/table-data').then(r => r.json())
return (
<div style={{ padding: 24 }}>
<h1>Management Dashboard</h1>
<div style={{ marginBottom: 16 }}>
<DatePicker />
</div>
<DataTable data={data} />
</div>
)
}
export default DashboardPage
// components/DataTable.tsx - Complete Table Component
'use client'
import { Table, Tag, Space, Button, Popconfirm } from 'antd'
import type { ColumnsType } from 'antd/es/table'
interface UserData {
key: number
name: string
age: number
address: string
status: 'active' | 'inactive'
}
function DataTable({ data }: { data: UserData[] }) {
const columns: ColumnsType<UserData> = [
{ title: 'Name', dataIndex: 'name', key: 'name', sorter: (a, b) => a.name.localeCompare(b.name) },
{ title: 'Age', dataIndex: 'age', key: 'age', sorter: (a, b) => a.age - b.age },
{ title: 'Address', dataIndex: 'address', key: 'address' },
{
title: 'Status',
dataIndex: 'status',
key: 'status',
render: (status: string) => (
<Tag color={status === 'active' ? 'green' : 'red'}>
{status === 'active' ? 'Enable' : 'Disable'}
</Tag>
),
},
{
title: 'Operation',
key: 'action',
render: (_: any, record: UserData) => (
<Space>
<Button type="link" onClick={() => console.log('Edit', record.key)}>Edit</Button>
<Popconfirm title="Confirm Deletion?" onConfirm={() => console.log('Delete', record.key)}>
<Button type="link" danger>Delete</Button>
</Popconfirm>
</Space>
),
},
]
return (
<Table
columns={columns}
dataSource={data}
pagination={{ pageSize: 10, showSizeChanger: true, showTotal: (total) => `Total ${total} items` }}
bordered
size="middle"
/>
)
}
export default DataTable
(3) واجهة مستخدم بدون رأس + تخصيص Tailwind CSS
تقدم «Headless UI» نهجًا مختلفًا تمامًا لمكتبات المكونات — المكونات الخالية من الأنماط. فهي تكشف عن المنطق السلوكي (مثل إغلاق مربع الحوار المفتوح بالضغط على مفتاح Escape، والتنقل باستخدام لوحة المفاتيح في مربعات القائمة المنسدلة، وإدارة الرسوم المتحركة للانتقالات)، بينما تترك مسألة التصميم بالكامل للمطور. وهذا يعني أن واجهة المستخدم الخاصة بك يمكن أن تتطابق تمامًا مع نماذج التصميم دون الحاجة إلى تجاوز الأنماط الافتراضية الخاصة بأطراف ثالثة.
واجه توم بعض الحالات التي لم يغطِّها Ant Design: لوحة تصفية مخصصة تتطلب تفاعلات محددة، ومربع اقتراحات منسدل لنتائج البحث يحتاج إلى تصميم خاص. ويمكن تنفيذ هذين العنصرين بمرونة كبيرة باستخدام Headless UI. وبالاقتران مع فئات الأدوات المساعدة في Tailwind CSS، يمكنك إنشاء واجهة مستخدم تتطابق مع نماذج التصميم دون كتابة سطر واحد من CSS المخصص.
| مكونات واجهة المستخدم غير المرتبطة برأس | منطق السلوك المُقدَّم | الأجزاء التي تتطلب تخصيصًا |
|---|---|---|
| مربع الحوار | مفتاح Escape: إغلاق، تثبيت التركيز، تعطيل التمرير في الخلفية | المظهر، الرسوم المتحركة، نمط القناع |
| مربع القائمة المنسدلة | التنقل باستخدام لوحة المفاتيح، والبحث والتصفية، وتمييز الخيارات | حقول الإدخال، والألواح المنسدلة، وأنماط الخيارات |
| القائمة | التنقل باستخدام مفاتيح الأسهم؛ انقر خارجها لإغلاقها | عناصر القائمة والأيقونات وأنماط الفواصل |
| زر التبديل | حالة التبديل، ميزات الوصول (ARIA) | تبديل المسار، نمط شريط التمرير |
| مجموعة علامات التبويب | التنقل باستخدام مفاتيح الأسهم، ومزامنة اللوحات | أنماط تخطيط علامات التبويب واللوحات |
| الانتقال | إدارة الرسوم المتحركة للتلاشي التدريجي عند الظهور/التلاشي التدريجي عند الاختفاء | أسماء فئات CSS للرسوم المتحركة |
▶ المثال 3: مكونات واجهة المستخدم المخصصة بدون واجهة عرض
// components/SearchCombobox.tsx
// Usage Headless UI 's Combobox Implementing a search suggestion drop-down menu
'use client'
import { useState } from 'react'
import {
Combobox,
ComboboxInput,
ComboboxButton,
ComboboxOptions,
ComboboxOption,
Transition,
} from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
const people = [
{ id: 1, name: 'Alice', role: 'Admin' },
{ id: 2, name: 'Bob', role: 'Editor' },
{ id: 3, name: 'Charlie', role: 'Author' },
{ id: 4, name: 'Diana', role: 'Reader' },
{ id: 5, name: 'Eve', role: 'Admin' },
]
function SearchCombobox() {
const [selected, setSelected] = useState(people[0])
const [query, setQuery] = useState('')
const filtered = query === ''
? people
: people.filter((person) =>
person.name.toLowerCase().includes(query.toLowerCase())
)
return (
<div className="w-72">
<Combobox value={selected} onChange={setSelected}>
<div className="relative">
<ComboboxInput
className="w-full rounded-lg border border-gray-300 bg-white py-2 pl-3 pr-10 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
displayValue={(person: any) => person?.name}
onChange={(event) => setQuery(event.target.value)}
placeholder="Search Users..."
/>
<ComboboxButton className="absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronDownIcon className="h-5 w-5 text-gray-400" />
</ComboboxButton>
</div>
<Transition
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<ComboboxOptions className="absolute z-10 mt-1 max-h-60 w-72 overflow-auto rounded-lg bg-white py-1 shadow-lg ring-1 ring-black/5">
{filtered.length === 0 && query !== '' ? (
<div className="px-3 py-2 text-sm text-gray-500">No matching results found</div>
) : (
filtered.map((person) => (
<ComboboxOption
key={person.id}
value={person}
className="cursor-pointer px-3 py-2 text-sm data-[focus]:bg-blue-100 data-[selected]:bg-blue-50"
>
{({ selected }) => (
<div className="flex justify-between">
<span className={selected ? 'font-medium' : ''}>{person.name}</span>
<span className="text-gray-400">{person.role}</span>
</div>
)}
</ComboboxOption>
))
)}
</ComboboxOptions>
</Transition>
</Combobox>
{selected && (
<p className="mt-2 text-sm text-gray-600">
Selected:{selected.name}({selected.role})
</p>
)}
</div>
)
}
export default SearchCombobox
▶ المثال 4: إعدادات تحسين الأداء في ملف next.config.ts
// next.config.ts - Performance Optimization Configuration for the Component Library
import type { NextConfig } from 'next'
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
const nextConfig: NextConfig = withBundleAnalyzer({
optimizePackageImports: [
'antd',
'@ant-design/icons',
'@mui/material',
'@mui/icons-material',
'@headlessui/react',
],
transpilePackages: ['antd'],
experimental: {
optimizeCss: true,
},
})
export default nextConfig
// package.json scripts:
// "analyze": "ANALYZE=true next build"
// "analyze:server": "ANALYZE=true BUNDLE_ANALYZE=server next build"
// "analyze:browser": "ANALYZE=true BUNDLE_ANALYZE=browser next build"
▶ المثال 5: استراتيجيات لدمج ومطابقة مكتبات مكونات متعددة
// components/HybridTable.tsx - Ant Design Table + Headless UI Custom Filters
'use client'
import { useState } from 'react'
import { Table, Tag } from 'antd'
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react'
import type { ColumnsType } from 'antd/es/table'
interface Product {
key: string
name: string
price: number
category: string
status: 'in_stock' | 'out_of_stock'
}
const products: Product[] = [
{ key: '1', name: 'Laptop', price: 999, category: 'Electronics', status: 'in_stock' },
{ key: '2', name: 'Desk Chair', price: 299, category: 'Furniture', status: 'out_of_stock' },
{ key: '3', name: 'Coffee Maker', price: 79, category: 'Kitchen', status: 'in_stock' },
]
function HybridTable() {
const [categoryFilter, setCategoryFilter] = useState<string>('all')
const filtered = categoryFilter === 'all'
? products
: products.filter(p => p.category === categoryFilter)
const columns: ColumnsType<Product> = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Price', dataIndex: 'price', key: 'price', render: (v: number) => `$${v}` },
{ title: 'Category', dataIndex: 'category', key: 'category' },
{
title: 'Status',
dataIndex: 'status',
key: 'status',
render: (s: string) => (
<Tag color={s === 'in_stock' ? 'green' : 'red'}>
{s === 'in_stock' ? 'In Stock' : 'Out of Stock'}
</Tag>
),
},
]
return (
<div>
<div className="mb-4 flex items-center gap-2">
<Popover className="relative">
<PopoverButton className="rounded border px-3 py-1.5 text-sm">
Filter: {categoryFilter === 'all' ? 'All' : categoryFilter}
</PopoverButton>
<PopoverPanel className="absolute z-10 mt-1 w-40 rounded bg-white py-1 shadow-lg">
{['all', 'Electronics', 'Furniture', 'Kitchen'].map(cat => (
<button
key={cat}
className="block w-full px-3 py-1.5 text-left text-sm hover:bg-blue-50"
onClick={() => setCategoryFilter(cat)}
>
{cat === 'all' ? 'All Categories' : cat}
</button>
))}
</PopoverPanel>
</Popover>
</div>
<Table columns={columns} dataSource={filtered} pagination={false} size="small" />
</div>
)
}
export default HybridTable
❓ أسئلة شائعة
'use client')؛ ولا يمكن استخدامها مباشرةً في مكونات الخادم؛ ثانيًا، استخدم dynamic لاستيراد المكونات ديناميكيًا لتجنب تجميع مكتبة antd بأكملها في جافا سكريبت «فوق الطي»؛ ثالثًا، قم بتكوين السمات والتدويل في ConfigProvider لضمان اتساق الأنماط على المستوى العام. لم يعد Ant Design v5 يتطلب babel-plugin-import، حيث يتم تمكين Tree Shaking تلقائيًا.dynamic لتحميل المكونات عند الحاجة (dynamic(() => import('antd').then(m => m.Button)))؛ قم بتكوين optimizePackageImports في next.config.ts؛ استورد المكونات التي تحتاجها فقط (import { Button } from 'antd' بدلاً من استيراد كل شيء)؛ تحليل حجم الحزمة (@next/bundle-analyzer) لتحديد التبعيات غير الطبيعية. بعد التحسين، لا يتجاوز تأثير دمج Ant Design على جافا سكريبت للشاشة الأولى عادةً 30 كيلوبايت.ConfigProvider وMaterial UI ThemeProvider يوفران أنظمة سمات شاملة تتيح لك تجاوز الرموز (tokens) مثل الألوان، والمسافات، والزوايا الدائرية، والخطوط. استخدم CSS Modules أو Tailwind لتكملة الأنماط التي لا يغطيها نظام السمات الخاص بمكتبة المكونات. تجنب استخدام !important لتجاوز أنماط مكتبة المكونات — يجب أن تحقق ذلك باستخدام رموز السمات أو تجاوز متغيرات CSS.babel-plugin-import. بالإضافة إلى ذلك، تقدم الإصدارة v5 المكون App (الذي يدير مركزياً الطرق الثابتة مثل message وnotification وmodal)، والكائن theme (لتخصيص الرموز بدقة)، ودعم محسّن لـ SSR. كما أصبحت تعريفات أنواع TypeScript في الإصدار 5 أكثر شمولاً. إذا كنت تقوم بالترقية من الإصدار 4، فتأكد من الانتباه إلى توافق CSS-in-JS والتغييرات التي طرأت على واجهة برمجة تطبيقات السمات (theme API).📖 ملخص
- يُعد Ant Design مناسبًا لأنظمة الخلفية والبرمجيات الوسيطة على مستوى المؤسسات؛ فهو يوفر مجموعة شاملة من المكونات، وأفضل نظام بيئي لـ React، وحلول تكامل متطورة لـ Next.js.
- تم تصميم Material UI للتطبيقات الموجهة للمستهلكين، ويتميز بنظام تصميم متطور، ونظام سمات قوي، وأسلوب بصري عصري
- توفر واجهة المستخدم «Headless UI» مكونات سلوكية خالية من الأنماط، مما يجعلها مناسبة للمشاريع التي تتطلب درجة عالية من التخصيص؛ وغالبًا ما تُستخدم بالاقتران مع Tailwind CSS
- أفضل الممارسات لاستخدام Ant Design في Next.js:
'use client'الإعلان +dynamicالاستيراد الديناميكي +ConfigProviderتكوين السمة - تعمل ميزة «Tree Shaking» تلقائيًا مع وحدات ES؛ ولا يلزم إجراء أي إعدادات إضافية لـ
babel-plugin-import. - يمكن أن يؤدي تحسين
next.config.tsالخاص بـoptimizePackageImportsإلى تقليل حجم حزمة مكتبة المكونات - ثلاثة عوامل رئيسية لاختيار مكتبة المكونات: نوع المشروع (الخلفية/الواجهة الأمامية)، ومتطلبات التخصيص (قياسية/مخصصة بدرجة عالية)، وخلفية الفريق (React/موجهة نحو التصميم)
- يمكن استخدام عدة مكتبات للمكونات معًا: يوفر Ant Design مكونات قياسية، بينما تكملها Headless UI بمكونات مخصصة
- يستخدم Ant Design v5 نهج CSS-in-JS، لذا لم يعد هناك حاجة إلى مُركِّب Less و babel-plugin-import.
optimizePackageImportsضبط الإعدادات لتحسين حجم حزمة مكتبة المكونات وتقليل حجم جافا سكريبت الذي يتم تحميله عند ظهور الشاشة الأولى- يمكن لمكون «Transition» في «Headless UI»، عند استخدامه مع «Tailwind»، إنشاء رسوم متحركة سلسة للدخول والخروج.
- عند اختيار مكتبة مكونات، ينبغي أولاً تجربتها في مشروع تجريبي وتقييمها بناءً على ثلاثة معايير: كفاءة التطوير، وتأثيرها على الأداء، ومنحنى التعلم.
- يتناول هذا الدرس أساسيات واجهة المستخدم الخاصة بالمشروع المتكامل (SaaS Kanban) الذي سيتم تناوله في الدرس التالي.
📝 تمارين
- دمج Ant Design في واجهة إدارة المدونة: قم بإنشاء سمة
providers.tsxمُهيأة لـ Ant Design والتدويل (مضبوطة على اللغة الصينية)، وقم بتضمينها في التخطيط العامAntdProvider. استخدم مكونات مثلButtonوTableوTagوSpaceلإعادة تصميم صفحة إدارة المستخدمين في المدونة ضمن واجهة الإدارة. - استخدم المكون
Comboboxمن Headless UI + Tailwind CSS لتنفيذ أداة اختيار البحث عن المستخدمين: استرجاع قائمة بالمستخدمين من واجهة برمجة التطبيقات (API)، ودعم البحث والتصفية باستخدام الكلمات المفتاحية، وعرض معلومات المستخدم عند اختيار أحد المستخدمين. قارن ذلك بمكونSelectمن Ant Design لتجربة مستوى مرونة التخصيص الذي يوفره Headless UI. - تحسين أداء مكتبة المكونات الخاصة بالمشروع: استخدم
@next/bundle-analyzerلتحليل التغيرات في حجم الحزمة قبل وبعد دمج Ant Design. قم بتحويل ثلاثة مكونات كبيرة على الأقل (DatePicker، Table، TreeSelect) إلى التحميل الديناميكي باستخدامdynamic. أضفoptimizePackageImports: ['antd', '@ant-design/icons']إلىnext.config.tsوقارن حجم JavaScript للشاشة الأولى ونتائج أداء Lighthouse قبل التحسين وبعده.