
shadcn/ui تطلق cn: محرك مدمج لدمج فئات Tailwind بسرعة تتجاوز 30 ضعفا
تعتمد معظم تطبيقات الويب الحديثة المبنية على Tailwind CSS ومكونات shadcn/ui على دالة مساعدة شائعة تُعرف باسم cn(...). تُستخدم هذه الدالة للجمع بين الأسماء الشرطية للفئات البرمجية وفض التعارض بين فئات Tailwind المتنافسة، مثل ضمان تفوق فئة الهوامش الداخلية p-4 على p-2. اعتمدت هذه الدالة تاريخيا على الدمج بين مكتبتين: clsx لتجميع الشروط، وtailwind-merge لفض التعارضات. رغم فاعلية هذا النموذج، فإنه يفرض عبئا خفيا متكررا داخل حلقات التصيير (Render Loops).
في 3 سبتمبر 2026، أعلن مطور shadcn بالتعاون مع مهندس تحسين الأداء aidenybai إطلاق محرك cn (الإصدار 0.2.4 عبر npm)، وهو محرك مفتوح المصدر تم بناؤه من الصفر ليكون بديلا مباشرا لمكتبتي clsx وtailwind-merge. يأتي المحرك دون أي اعتماديات خارجية (Zero Dependencies)، ويقدم مطابقة كاملة لواجهة الاستخدام البرمجية وحالات الاختبار، مع تسريع تنفيذ الاستدعاءات النمطية داخل المكونات بمعدل يصل إلى 30 ضعفا.
العبء الخفي لمعالجة الفئات أثناء التشغيل
لكي تتمكن أداة مثل tailwind-merge من حسم التعارضات بدقة، يجب أن تفهم كامل مواصفات فئات Tailwind التي تشمل نحو 380 مجموعة فئات برمجية. في الهيكلية التقليدية، تُشحن هذه القواعد ككائن إعدادات كبير (Configuration Object)، ويقوم المتصفح بتفسيره سطرا بسطر أثناء تشغيل التطبيق.
مع كل إعادة تصيير لأي مكون في واجهة المستخدم:
- تُقسّم النصوص المدخلة عبر المسافات البيضاء إلى عناصر منفردة.
- يُقسّم كل عنصر عبر الشرطات، وتُفحص شجرة متداخلة (Map Trie) لتحديد مجموعة الفئة.
- تُنفّذ تعابير نمطية (Regular Expressions) نشطة للتحقق من القيم العشوائية والمعدلات الرقمية.
- تُسجل التعارضات وتُحسم باستخدام مفاتيح نصية، مما يولد نصوصا وسيطة وكائنات مؤقتة تستهلك الذاكرة.
في لوحات التحكم المعقدة أو الجداول البيانية التي تضم مئات العناصر التفاعلية، يتكرر هذا المسار آلاف المرات في الثانية. يستغرق الاستدعاء النمطي في tailwind-merge قرابة 320 نانوثانية، مما يشكل ضغطا إضافيا على مجمع النفايات البرمجية (Garbage Collector)، لا سيما في متصفحات الهواتف المحمولة محدودة الموارد.
كيف يعمل محرك cn الجديد؟
بدلا من نقل قواعد الفئات المعقدة إلى متصفح المستخدم وتفسيرها أثناء التشغيل، ينقل محرك cn هذه المعالجة بالكامل إلى مرحلة البناء والتجميع (Compile-time).
يقوم محول برمجي متخصص بمعالجة قواعد فض التعارض في Tailwind مرة واحدة فقط أثناء بناء الحزمة، ثم يُنتج جداول بحث مسطحة (Flat Lookup Tables) مخزنة في مصفوفات رقمية محددة الأنواع (Typed Arrays). يعمل المحرك بعد ذلك من خلال مسار قراءة أحادي مباشر:
- شجرة رموز في مصفوفات رقمية: تُطابق الرموز عبر مصفوفات أعداد صحيحة بدلا من التنقل بين كائنات جافاسكريبت المتداخلة.
- مقارنات بالأعداد الصحيحة: يُحسم التعارض وتُكتشف التباينات عبر مقارنات حسابية سريعة للأعداد بدلا من البحث النصي.
- تقليل استهلاك الذاكرة: تُفحص أجزاء النصوص مباشرة دون استقطاع سلاسل وسيطة في الذاكرة. وفي حال عدم وجود أي تعارض بين الفئات، يُعيد المحرك مرجع النص الأصلي ذاته دون حجز أي بايت جديد.
ثلاث طبقات للذاكرة المؤقتة (Caching)
تتميز واجهات المستخدم بإعادة تصيير المكونات ذاتها بحالات مستقرة. استغل محرك cn هذا النمط المعماري عبر دمج ثلاث طبقات من الذاكرة المؤقتة:
- ذاكرة مؤشرات الوسائط (Argument Pointer Cache): تستدعي المكونات عادة الدالة بصيغة
cn(base, variant, cond && extra)باستخدام مؤشرات نصوص مطابقة عبر عمليات التصيير المتكررة. يتحقق المحرك من هوية المؤشرات، ويتعلم تسلسل الاستدعاءات البرمجية، مما يتيح تجاوز جداول البحث كليا وتنفيذ الاستدعاء في غضون 10 نانوثانية فقط. - ذاكرة النصوص الكاملة: لمنع استنزاف ذاكرة التصيير على جانب الخادم (SSR) عبر نصوص فريدة تُطلب لمرة واحدة، يشترط المحرك تكرار النص مرتين على الأقل قبل اعتماده في الذاكرة المؤقتة الأساسية.
- تخزين الرموز المتكررة: يُعاد استخدام التحليل المسبق للفئات الشائعة التي تتكرر داخل نصوص مركبة جديدة لتفادي إعادة فحصها.
نتائج القياس واختبارات التوافق
في الاختبارات المعيارية المعزولة على بيئة Node:
- استدعاء المكونات النمطي: انخفض زمن التنفيذ من 320 نانوثانية باستخدام
clsx + tailwind-mergeإلى 10 نانوثانية فقط معcn(تسريع بمقدار 30 ضعفا). - الاستدعاءات المتكررة في المشاريع الفعلية: انخفض الزمن من 2.4 ميكروثانية إلى 14 نانوثانية (تسريع يتجاوز 170 ضعفا).
- التهيئة الأولية عند بدء التشغيل: تحتاج
tailwind-mergeإلى نحو 3.2 ميلي ثانية لبناء شجرة التوزيع عند أول استدعاء، بينما ينهي محركcnتهيئة مصفوفاته في 0.4 ميلي ثانية فقط.
لقياس الأثر الواقعي بعيدا عن الاختبارات المعملية، نفذ الفريق اختبار bench:corpus، الذي قام بإعادة تشغيل 144,265 استدعاء فعليا تم جمعها من 58 مستودعا مفتوح المصدر قيد التشغيل الفعلي. حقق محرك cn متوسط تسريع هندسي قدره 37 ضعفا مقارنة بالمزيج التقليدي.
تأتي هذه السرعة مع ضمان عدم كسر السلوك البرمجي عبر منظومة اختبار تكامل مستمر تفحص 56,346 حالة مطابقة تامة مع مخرجات tailwind-merge، و300,000 سلسلة فئات عشوائية، و5,054 مجموعة إعدادات مخصصة.
تخصيص الجداول وفق احتياجات المشروع
يقدم محرك cn أمرا اختياريا يسمى cn build.
نظرا لأن المكتبات التقليدية تقدم قواعدها كواجهة عامة للمطورين، فإنها تضطر لشحن كافة المجموعات البالغ عددها 380 فئة. يتيح أمر cn build فحص ملفات الكود المصدري في مشروعك، وتحديد الفئات المستخدمة فعليا، ثم إعادة توليد جداول بحث مخصصة تحتوي فقط على الفئات المطلوبة، وحذف الباقي، مما يقلل حجم الحزمة المشحونة للمتصفح دون المساس بصحة المخرجات.
خطوات الترقية والانتقال
لا يتطلب الاعتماد على cn أي تعديل في خصائص المكونات أو طريقة استدعائها داخل الكود، وتتوفر الحزمة رسميا عبر مدير الحزم npm باسم cn.
بالنسبة للمشاريع التي تستخدم أداة shadcn CLI بالفعل، تتوفر ترقية تلقائية مباشرة:
npx shadcn@latest migrate cn
أما للترقية اليدوية، يتم تثبيت الحزمة عبر:
npm install cn
ثم تعديل الملف المساعد للمشروع (الموجود عادة في src/lib/utils.ts):
// قبل التحديث
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// بعد التحديث
export { cn } from "cn"
أما في حال استخدام قوالب تصميم موسعة تحتوي على فئات مخصصة خارج مواصفات Tailwind القياسية، يوفر مسار cn/config واجهة لإضافة القواعد الخاصة:
import { extendConfig } from "cn/config"
export const cn = extendConfig({
extend: {
classGroups: {
"font-size": [{ text: ["display-hero"] }],
},
},
})
ما يعنيه هذا التطور لفرق التطوير
يجسد محرك cn توجها هندسيا متزايدا في بيئة تطوير الويب: نقل العمليات الحسابية المكلفة من وقت التشغيل في المتصفح إلى وقت البناء والتجميع. في المشروعات الصغيرة، نادرا ما يمثل دمج أسماء الفئات عنق زجاجة ملحوظا، ولكن في المنظومات الكبيرة ومكتبات المكونات الشاملة والتطبيقات ذات الواجهات الكثيفة، فإن إلغاء فحص التعابير النمطية من كل دورة تصيير يسهم مباشرة في خفض الضغط على المعالج الرئيسي وتفادي البطء اللحظي أثناء التفاعل السريع.
المشروع مرخص برخصة MIT المفتوحة ومتاح للاستخدام الفوري.