الأداء والتحسين
الأداء والتحسين
تم تصميم Tailwind CSS للأداء، لكن تحتاج إلى تكوينه بشكل صحيح للحصول على أصغر إصدارات إنتاج ممكنة. تعلم كيف ينقي Tailwind CSS غير المستخدم، ويحسن الإخراج، وأفضل الممارسات للحفاظ على أوقات تحميل سريعة.
كيف ينقي Tailwind CSS غير المستخدم
يتضمن Tailwind آلاف فئات الأدوات المساعدة افتراضياً. في الإنتاج، معظم هذه الفئات لا تُستخدم أبداً. يستخدم Tailwind PurgeCSS لمسح ملفاتك وإزالة أي فئات غير مشار إليها في كودك.
حجم الإصدار الافتراضي مقابل الإنتاج
# إصدار التطوير (جميع الأدوات)
غير مضغوط: ~3.5 ميجابايت
مضغوط Gzip: ~400 كيلوبايت
# إصدار الإنتاج (منقى + مُصغّر)
غير مضغوط: ~10-30 كيلوبايت (نموذجي)
مضغوط Gzip: ~5-10 كيلوبايت (نموذجي)
# تقليل الحجم: ~97-99%
content بشكل صحيح، ويتولى Tailwind الباقي.
تكوين مسارات المحتوى
يخبر خيار content Tailwind بالملفات التي يجب فحصها للبحث عن أسماء الفئات. هذا هو التكوين الأكثر أهمية للتحسين:
تكوين المحتوى في tailwind.config.js
// tailwind.config.js
module.exports = {
content: [
// قوالب HTML
'./index.html',
'./src/**/*.html',
// ملفات JavaScript/TypeScript
'./src/**/*.{js,jsx,ts,tsx}',
// مكونات Vue
'./src/**/*.vue',
// مكونات Svelte
'./src/**/*.svelte',
// قوالب PHP (Laravel, WordPress, إلخ)
'./resources/**/*.blade.php',
'./app/**/*.php',
// محركات قوالب أخرى
'./templates/**/*.twig',
'./views/**/*.ejs',
],
theme: {
extend: {},
},
plugins: [],
}
أفضل ممارسات تكوين المحتوى
اتبع هذه الأنماط للحصول على مسح محتوى مثالي:
تكوين محتوى متقدم
// tailwind.config.js
module.exports = {
content: {
files: [
'./src/**/*.{html,js,jsx,ts,tsx,vue}',
'./components/**/*.{js,jsx,ts,tsx}',
'./pages/**/*.{js,jsx,ts,tsx}',
],
// استخراج الفئات من أنماط محددة
extract: {
// استخراج مخصص لصيغة خاصة
js: {
pattern: /class(?:Name)?=["'`]([^"'`]*)/g,
transform: (match) => match,
},
},
// تحويل المحتوى قبل المسح
transform: {
md: (content) => {
return content.replace(/\.md$/, '');
},
},
},
theme: {
extend: {},
},
plugins: [],
}
عملية بناء الإنتاج
إليك كيفية إنشاء إصدارات إنتاج محسّنة مع أدوات بناء مختلفة:
إصدارات الإنتاج مع أدوات متنوعة
# Vite
NODE_ENV=production npm run build
# أو
npm run build # (Vite يعين NODE_ENV تلقائياً)
# Webpack
NODE_ENV=production webpack --mode production
# Parcel
parcel build src/index.html
# Next.js
next build
# Create React App
npm run build
# Vue CLI
npm run build
# Laravel Mix
npm run production
process.env.NODE_ENV === 'production' لتمكين التنقية والتصغير. تأكد دائماً من أن أداة البناء الخاصة بك تعين هذا بشكل صحيح.
فهم خط أنابيب البناء
يمر إصدار إنتاج Tailwind بعدة مراحل تحسين:
مراحل خط أنابيب البناء
1. مسح المحتوى
↓
يمسح جميع الملفات في مسارات المحتوى
يستخرج أسماء الفئات باستخدام أنماط regex
يبني قائمة بالفئات المستخدمة
2. إنشاء CSS
↓
ينشئ CSS فقط للفئات المستخدمة
يزيل الأدوات والمكونات والأنماط الأساسية غير المستخدمة
يطبق تخصيصات السمة
3. التنقية
↓
يزيل قواعد CSS غير المستخدمة
يحتفظ فقط بالفئات الموجودة في ملفات المحتوى
يحافظ على فئات القائمة الآمنة
4. التحسين
↓
يصغر CSS (يزيل المسافات البيضاء، التعليقات)
يدمج القواعد المكررة
يحسن المحددات
5. AUTOPREFIXER
↓
يضيف بادئات الموردين
يستهدف المتصفحات من تكوين browserslist
يضمن التوافق عبر المتصفحات
6. الإخراج
↓
ملف CSS محسّن نهائي (~5-30 كيلوبايت نموذجي)
تحليل حجم الإخراج
راقب حجم حزمة CSS الخاصة بك لاكتشاف مشاكل التحسين:
أوامر تحليل الحجم
# حجم الملف الأساسي
ls -lh dist/css/main.css
# الحجم المضغوط Gzip (ما يقوم المستخدمون بتنزيله فعلياً)
gzip -c dist/css/main.css | wc -c
# استخدام أدوات البناء
npx vite build --analyze # Vite
webpack-bundle-analyzer dist # Webpack
# التحليل اليدوي مع PostCSS
npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify
# عرض إحصائيات مفصلة
du -h dist/css/main.css
تجنب إنشاء الفئات الديناميكية
أحد أكبر المخاطر في التحسين هو إنشاء أسماء الفئات ديناميكياً. هذا يمنع التنقية الصحيحة:
لا تفعل: أسماء الفئات الديناميكية (لن تعمل)
// ❌ سيئ: Tailwind لا يمكنه اكتشاف هذه
const Button = ({ color }) => {
return (
<button className={`bg-${color}-500 text-white`}>
Click me
</button>
);
};
// ❌ سيئ: الاستيفاء النصي
const Alert = ({ type }) => {
return (
<div className={`border-${type}-300 bg-${type}-50`}>
Alert
</div>
);
};
// ❌ سيئ: أسماء الفئات المحسوبة
const sizes = ['sm', 'md', 'lg'];
const Box = ({ size }) => {
return <div className={`p-${sizes[size]}`}>Box</div>;
};
افعل: أسماء الفئات الكاملة (يعمل بشكل صحيح)
// ✅ جيد: أسماء الفئات الكاملة
const Button = ({ color }) => {
const colors = {
blue: 'bg-blue-500 text-white',
red: 'bg-red-500 text-white',
green: 'bg-green-500 text-white',
};
return (
<button className={colors[color]}>
Click me
</button>
);
};
// ✅ جيد: شرطي مع أسماء كاملة
const Alert = ({ type }) => {
return (
<div className={
type === 'error' ? 'border-red-300 bg-red-50' :
type === 'warning' ? 'border-yellow-300 bg-yellow-50' :
'border-blue-300 bg-blue-50'
}>
Alert
</div>
);
};
// ✅ جيد: تعيين الكائنات
const Box = ({ size }) => {
const sizeClasses = {
sm: 'p-2',
md: 'p-4',
lg: 'p-8',
};
return <div className={sizeClasses[size]}>Box</div>;
};
إدراج الفئات في القائمة الآمنة
إذا كان يجب عليك استخدام فئات ديناميكية (من CMS، قاعدة بيانات، إلخ)، استخدم خيار القائمة الآمنة:
تكوين القائمة الآمنة
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{html,js}'],
safelist: [
// فئات محددة
'bg-red-500',
'text-3xl',
'lg:text-4xl',
// مطابقة الأنماط
{
pattern: /bg-(red|green|blue)-(400|500|600)/,
variants: ['hover', 'focus'],
},
// جميع المتغيرات من فئات محددة
{
pattern: /text-(center|left|right)/,
variants: ['sm', 'md', 'lg', 'xl', '2xl'],
},
// الحفاظ على لوحات الألوان الكاملة
{
pattern: /^bg-/,
variants: ['hover'],
},
],
theme: {
extend: {},
},
plugins: [],
}
التخلص من الأشجار والقضاء على الكود الميت
يمكن للمجمعات الحديثة إزالة الكود غير المستخدم، لكن تحتاج إلى كتابة كود قابل للتخلص من الأشجار:
أنماط الكود القابلة للتخلص من الأشجار
// ✅ جيد: الصادرات المسماة (قابلة للتخلص من الأشجار)
// utils/buttons.js
export function PrimaryButton() { /*...*/ }
export function SecondaryButton() { /*...*/ }
export function DangerButton() { /*...*/ }
// يستورد فقط ما تستخدمه
import { PrimaryButton } from './utils/buttons';
// ❌ سيئ: الصادر الافتراضي مع كائن (ليس قابل للتخلص من الأشجار)
// utils/buttons.js
export default {
PrimaryButton: () => { /*...*/ },
SecondaryButton: () => { /*...*/ },
DangerButton: () => { /*...*/ },
};
// يستورد كل شيء
import Buttons from './utils/buttons';
const { PrimaryButton } = Buttons;
نصائح تحسين حجم ملف CSS
استراتيجيات إضافية للحفاظ على CSS الخاص بك صغيراً:
استراتيجيات التحسين
1. قلل الأدوات المخصصة
// ❌ لا تضف مئات الأدوات المخصصة
theme: {
extend: {
spacing: {
'13': '3.25rem',
'15': '3.75rem',
'128': '32rem',
'144': '36rem',
// ... 50 قيمة مخصصة أخرى
}
}
}
// ✅ أضف فقط ما تستخدمه بالفعل
theme: {
extend: {
spacing: {
'128': '32rem',
}
}
}
2. استخدم الإضافات بشكل انتقائي
// ❌ لا تقم بتضمين جميع الإضافات
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
require('@tailwindcss/aspect-ratio'),
require('@tailwindcss/container-queries'),
// ... المزيد من الإضافات
]
// ✅ قم بتضمين الإضافات التي تستخدمها بنشاط فقط
plugins: [
require('@tailwindcss/forms'),
]
3. عطّل المتغيرات غير المستخدمة
// ❌ لا تُمكّن المتغيرات التي لا تحتاجها
variants: {
extend: {
backgroundColor: ['active', 'group-hover', 'peer-checked'],
}
}
// ✅ قم بتوسيع المتغيرات فقط عند الضرورة
// المتغيرات الافتراضية عادة ما تكون كافية
4. قلل لوحة الألوان
// ❌ لا تقم بتضمين جميع الدرجات إذا كنت تستخدم القليل فقط
colors: {
blue: {
50: '#eff6ff',
100: '#dbeafe',
// ... جميع الدرجات العشرة
900: '#1e3a8a',
}
}
// ✅ حدد فقط الدرجات التي تستخدمها
colors: {
blue: {
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
}
}
اعتبارات التحميل البطيء
للتطبيقات الكبيرة، فكر في تقسيم الكود والتحميل البطيء:
استراتيجيات تقسيم كود CSS
// 1. التقسيم على مستوى المكون (React)
const HeavyComponent = lazy(() => import('./HeavyComponent'));
// 2. التقسيم القائم على المسار (React Router)
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Profile = lazy(() => import('./pages/Profile'));
<Routes>
<Route path="/dashboard" element={
<Suspense fallback={<Loading />}>
<Dashboard />
</Suspense>
} />
</Routes>
// 3. CSS حاسم مضمن، الباقي غير متزامن (HTML)
<style>
/* CSS حاسم فوق الجزء المرئي مضمن */
.hero { /* ... */ }
</style>
<link rel="preload" href="/css/main.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
// 4. فصل CSS الأدوات عن المكونات
// tailwind.config.js
module.exports = {
corePlugins: {
preflight: false, // عطّل إذا كان لديك أنماط أساسية مخصصة
},
}
مراقبة أداء البناء
تتبع أوقات البناء الخاصة بك وحسن الأجزاء البطيئة:
مراقبة الأداء
# توقيت عمليات البناء الخاصة بك
time npm run build
# بناء Vite مع التوقيت
vite build --debug
# تحليل حزمة Webpack
npm install -D webpack-bundle-analyzer
// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
# توقيت PostCSS
DEBUG=* npx tailwindcss -i input.css -o output.css
# مقارنة الأحجام قبل/بعد
ls -lh dist/css/*.css | awk '{print $5 " " $9}'
bundlesize أو size-limit يمكنها فشل البناء إذا نما CSS بما يتجاوز عتبتك.
أخطاء التحسين الشائعة
تجنب هذه المخاطر الشائعة في الأداء:
الأنماط المضادة للأداء
// ❌ خطأ 1: عدم تعيين NODE_ENV
npm run build # بدون NODE_ENV=production
// ❌ خطأ 2: مسارات محتوى غير صحيحة
content: ['./src/*.js'] // أدلة فرعية مفقودة
// ❌ خطأ 3: تضمين node_modules
content: ['./node_modules/**/*.js'] // وقت مسح كبير
// ❌ خطأ 4: فئات ديناميكية في كل مكان
className={`text-${userColor}-500`} // لن يتم تنقيته بشكل صحيح
// ❌ خطأ 5: عدد كبير جداً من الأدوات المخصصة
theme: {
extend: {
// توليد أكثر من 100 فئة أداة جديدة
}
}
// ❌ خطأ 6: عدم التصغير
// مفقود postcss-cssnano أو تصغير أداة البناء
// ❌ خطأ 7: تحميل CSS الكامل في التطوير
// استخدام CSS الإنتاج في التطوير (HMR بطيء)
تمرين 1: تدقيق البناء الخاص بك
حلل إعداد Tailwind CSS الحالي الخاص بك:
- تحقق من حجم ملف CSS الإنتاج الخاص بك (غير مضغوط ومضغوط gzip)
- تحقق من أن مسارات المحتوى تتضمن جميع الملفات ذات الصلة
- ابحث عن أنماط إنشاء الفئات الديناميكية في كودك
- قِس وقت بناء الإنتاج الخاص بك
- وثّق أحجام الحزم الحالية كخط أساس
تمرين 2: تحسين تكوين المحتوى
حسّن تكوين المحتوى الخاص بك:
- راجع جميع مسارات المحتوى وأزل الأنماط غير الضرورية
- أضف أي أنواع ملفات أو أدلة مفقودة
- اختبر أن جميع الفئات المستخدمة في تطبيقك تظهر في البناء
- قِس حجم البناء قبل/بعد
تمرين 3: إعادة هيكلة الفئات الديناميكية
ابحث وأصلح إنشاء الفئات الديناميكية:
- ابحث في قاعدة الكود الخاصة بك عن قوالب حرفية مع فئات Tailwind
- أعد هيكلة الفئات الديناميكية لاستخدام تعيينات الكائنات
- أضف إدخالات القائمة الآمنة للفئات الديناميكية حقاً
- تحقق من أن جميع الفئات الضرورية لا تزال تظهر في الإنتاج
- قِس التأثير على حجم الحزمة