بسیاری از توسعهدهندگان جنگو با این سناریوی آشنا روبرو هستند: سایتی که روی سیستم لوکال سریع و روان اجرا میشود، اما گزارشهای Google Search Console داستانی کاملاً متفاوت را روایت میکنند. URLها با برچسبهای قرمز و هشداردهنده “Poor” برای معیارهای Core Web Vitals (CWV) مشخص شدهاند و شما را با این سوال تنها میگذارند که کجای کار اشتباه است. این دقیقاً نقطه شروع ما در این مطالعه موردی Core Web Vitals جنگو است. ما یک وبسایت فروشگاهی فرضی ساخته شده با جنگو و قالبهای سنتی (Django Templates) را بررسی میکنیم که با وجود عملکرد قابل قبول ظاهری، در آزمونهای واقعی کاربرمحور گوگل شکست خورده است.
هدف این مقاله، ارائه یک نقشه راه عملی و دقیق برای تبدیل این نمرات قرمز به سبز درخشان است. ما به صورت گامبهگام، مشکلات رایج عملکردی در سایتهای جنگویی را تشخیص داده، راهحلهای مشخص با نمونه کد ارائه میدهیم و نتایج قبل و بعد از بهینهسازی را نشان میدهیم. این یک سفر فنی برای passing CWV است که به شما نشان میدهد چگونه با ابزارهای خود جنگو و تکنیکهای استاندارد، تجربه کاربری سایت خود را به سطح مورد تایید گوگل برسانید و از مزایای رتبهبندی آن بهرهمند شوید.
تشخیص مشکل: آنالیز نمرات قرمز Core Web Vitals
فهرست مقاله
اولین قدم برای حل هر مشکلی، درک دقیق آن است. Core Web Vitals مجموعهای از سه معیار مشخص است که گوگل برای اندازهگیری تجربه کاربری واقعی در زمینه سرعت بارگذاری، تعاملپذیری و پایداری بصری استفاده میکند. تا تاریخ امروز (و با در نظر گرفتن بهروزرسانیهای سال ۲۰۲۴)، این معیارها عبارتند از:
- Largest Contentful Paint (LCP): سرعت بارگذاری. مدت زمانی که طول میکشد تا بزرگترین عنصر محتوایی (معمولاً یک تصویر بزرگ یا یک بلوک متنی) در دید کاربر ظاهر شود. مقدار “خوب” کمتر از ۲.۵ ثانیه است.
- Interaction to Next Paint (INP): تعاملپذیری. این معیار که جایگزین First Input Delay (FID) شده است، تأخیر کلی تمام تعاملات کاربر (کلیکها، تپها و ورودیهای کیبورد) با صفحه را اندازهگیری میکند. مقدار “خوب” کمتر از ۲۰۰ میلیثانیه است.
- Cumulative Layout Shift (CLS): پایداری بصری. میزان جابجایی غیرمنتظره عناصر در صفحه حین بارگذاری را اندازهگیری میکند. مقدار “خوب” کمتر از ۰.۱ است.
در وبسایت فروشگاهی مورد مطالعه ما، گزارش PageSpeed Insights نتایج زیر را نشان میدهد:
- LCP: 4.2s (Poor)
- INP: 350ms (Poor)
- CLS: 0.28 (Poor)
این نمرات قرمز نه تنها به معنای تجربه کاربری ضعیف است، بلکه یک سیگنال منفی قوی برای الگوریتمهای رتبهبندی گوگل، بهخصوص پس از بهروزرسانی Page Experience، محسوب میشود. حال بیایید دلایل هر یک از این مشکلات را ریشهیابی کنیم.
تحلیل Largest Contentful Paint (LCP): چرا بارگذاری ۴.۲ ثانیه طول میکشد؟
با استفاده از تب Performance در Chrome DevTools، متوجه میشویم که عنصر LCP، تصویر اصلی محصول (Hero Image) است. زنجیره رخدادهایی که منجر به این LCP ضعیف شدهاند عبارتند از:
- Time to First Byte (TTFB) بالا: سرور جنگوی ما حدود ۱.۲ ثانیه زمان نیاز دارد تا پاسخ اولیه HTML را تولید کند. این تأخیر به دلیل کوئریهای پیچیده دیتابیس برای دریافت محصولات مرتبط و عدم استفاده از کش است.
- رندر بلاکینگ (Render-Blocking): فایلهای CSS و JavaScript حجیم در
<head>صفحه قرار دارند و مرورگر را مجبور میکنند قبل از شروع به رندر کردن محتوا، آنها را دانلود و پردازش کند. - تصویر بهینهنشده: تصویر اصلی محصول یک فایل JPEG با حجم ۱.۲ مگابایت است که هیچگونه بهینهسازی روی آن انجام نشده است.
تحلیل Interaction to Next Paint (INP): چرا کلیکها با تأخیر پاسخ میدهند؟
مشکل INP بالا تقریباً همیشه به JavaScript سنگین در ترد اصلی (Main Thread) مربوط میشود. در سایت ما، چند عامل مقصر هستند:
- اسکریپتهای Third-Party: اسکریپت چت آنلاین و یک اسکریپت آنالیتیکس سنگین، ترد اصلی را برای مدت طولانی مسدود میکنند.
- Event Listenerهای ناکارآمد: کدهای مربوط به اعتبارسنجی فرم افزودن به سبد خرید و اسلایدر تصاویر محصول، محاسبات پیچیدهای را در لحظه تعامل کاربر انجام میدهند و باعث تأخir در پاسخدهی بصری میشوند.
تحلیل Cumulative Layout Shift (CLS): چرا صفحه هنگام بارگذاری میپرد؟
CLS بالا تجربه کاربری آزاردهندهای ایجاد میکند. در سایت ما، دلایل اصلی عبارتند از:
- تصاویر بدون ابعاد مشخص: تگهای
<img>برای گالری تصاویر محصول فاقد اتریبیوتهایwidthوheightهستند. مرورگر تا زمان دانلود کامل تصاویر، فضایی برای آنها رزرو نمیکند و پس از دانلود، محتوای اطراف را به پایین هل میدهد. - محتوای دینامیک تزریقشده: یک بنر تبلیغاتی که از طریق جاوااسکریپت و پس از بارگذاری اولیه صفحه اضافه میشود، باعث جابجایی ناگهانی محتوای اصلی میشود.
- بارگذاری فونتها (FOIT): فونتهای سفارشی سایت باعث ایجاد پدیده Flash of Invisible Text میشوند. متن تا زمان دانلود فونت نامرئی است و پس از اعمال فونت، ابعاد بلوک متنی تغییر کرده و باعث شیفت میشود.
برنامه عملیاتی: سفر گامبهگام بهینهسازی جنگو
اکنون که مشکلات را شناسایی کردیم، زمان آن رسیده که با مجموعهای از optimization techniques used در جنگو، آنها را برطرف کنیم. ما به ترتیب روی هر یک از معیارهای CWV کار خواهیم کرد.
رفع مشکل LCP: از بارگذاری کند تا نمایش آنی
هدف ما رساندن LCP به زیر ۲.۵ ثانیه است. این کار را در سه مرحله انجام میدهیم.
مرحله اول: کاهش TTFB با کشینگ و بهینهسازی کوئری
کاهش TTFB بیشترین تأثیر را در بهبود LCP دارد. اولین قدم، استفاده از سیستم کش داخلی جنگو است.
- پیادهسازی View Caching: برای صفحه محصول که محتوای آن به ندرت تغییر میکند، میتوانیم کل خروجی View را کش کنیم.
در settings.py:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': '127.0.0.1:11211',
}
}
در views.py:
# Before
# def product_detail_view(request, slug):
# # ... complex queries ...
# return render(request, 'product_detail.html', context)
# After
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # Cache for 15 minutes
def product_detail_view(request, slug):
# ... complex queries ...
return render(request, 'product_detail.html', context)
- بهینهسازی کوئریهای دیتابیس: مشکل N+1 یک قاتل عملکرد در جنگو است. با استفاده از
select_relatedوprefetch_relatedمیتوانیم تعداد کوئریها را به شدت کاهش دهیم.
# Before: Triggers N+1 queries for category and tags
products = Product.objects.all()[:10]
# After: Fetches related objects in a single query
products = Product.objects.select_related('category').prefetch_related('tags').all()[:10]
نتیجه: با این دو تغییر، TTFB از ۱.۲ ثانیه به ۲۰۰ میلیثانیه کاهش یافت. این یک پیشرفت عظیم در Django performance است.
مرحله دوم: رام کردن تصویر اصلی (LCP Element)
اکنون باید خود تصویر را بهینه کنیم.
- استفاده از
django-imagekitبرای تصاویر واکنشگرا و فرمتهای مدرن: این پکیج قدرتمند به ما اجازه میدهد تا به صورت خودکار تصاویر را در اندازههای مختلف و با فرمت WebP (که حجم بسیار کمتری دارد) تولید کنیم.
در models.py:
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
class Product(models.Model):
# ...
image = models.ImageField(upload_to='products/')
image_medium = ImageSpecField(source='image',
processors=[ResizeToFill(800, 800)],
format='WEBP',
options={'quality': 80})
در تمپلیت:
<!-- Before -->
<img src="{{ product.image.url }}" alt="{{ product.name }}">
<!-- After -->
<picture>
<source srcset="{{ product.image_medium.url }}" type="image/webp">
<img src="{{ product.original_image.url }}" alt="{{ product.name }}" width="800" height="800">
</picture>
مرحله سوم: پیشبارگذاری (Preload) منبع LCP
برای اینکه مرورگر هرچه سریعتر دانلود تصویر اصلی را شروع کند، از تگ <link rel="preload"> استفاده میکنیم.
در تمپلیت اصلی base.html:
<head>
...
{% if lcp_image_url %}
<link rel="preload" as="image" href="{{ lcp_image_url }}" fetchpriority="high">
{% endif %}
...
</head>
و در views.py، آدرس تصویر اصلی را به context اضافه میکنیم تا در تمپلیت پایه در دسترس باشد.
نتیجه LCP: با اجرای این سه مرحله، LCP از ۴.۲ ثانیه به ۱.۹ ثانیه کاهش یافت و از “Poor” به “Good” تغییر وضعیت داد.
رفع مشکل INP: از کلیکهای بیجواب تا تعامل آنی
برای بهبود INP، باید بار کاری ترد اصلی جاوااسکریپت را کاهش دهیم.
- تعویق اسکریپتهای غیرضروری: تمام اسکریپتهایی که برای رندر اولیه صفحه حیاتی نیستند، باید با اتریبیوت
deferبارگذاری شوند. این کار مانع از بلاک شدن رندر HTML میشود.
در تمپلیت base.html:
<!-- Before -->
<script src="{% static 'js/chat-widget.js' %}"></script>
<script src="{% static 'js/main-bundle.js' %}"></script>
<!-- After -->
<script src="{% static 'js/chat-widget.js' %}" defer></script>
<script src="{% static 'js/main-bundle.js' %}" defer></script>
- تقسیم وظایف سنگین جاوااسکریپت: به جای اجرای یک تابع سنگین به صورت یکجا، آن را به بخشهای کوچکتر تقسیم کرده و با
setTimeoutبین آنها به مرورگر فرصت تنفس میدهیم تا به تعاملات کاربر پاسخ دهد. این تکنیک به ترد اصلی اجازه میدهد تا واکنشگرا باقی بماند.
نتیجه INP: با به تعویق انداختن اسکریپتهای Third-party و بهینهسازی کدهای خودمان، INP از ۳۵۰ میلیثانیه به ۱۵۰ میلیثانیه کاهش یافت و به محدوده “Good” وارد شد.
رفع مشکل CLS: از چیدمان لرزان تا پایداری بصری
هدف ما رساندن CLS به زیر ۰.۱ است.
- تعیین ابعاد برای مدیا: این سادهترین و مؤثرترین راه برای رفع CLS است. همیشه اتریبیوتهای
widthوheightرا برای تگهای<img>و<iframe>مشخص کنید. پکیجdjango-imagekitمیتواند این ابعاد را به صورت خودکار در اختیار ما قرار دهد.
در تمپلیت گالری:
<!-- Before -->
<img src="{{ image.url }}">
<!-- After: imagekit provides width and height -->
<img src="{{ image.url }}" width="{{ image.width }}" height="{{ image.height }}" style="aspect-ratio: {{ image.width }}/{{ image.height }};">
استفاده از CSS aspect-ratio یک لایه حفاظتی اضافه میکند تا فضای لازم حتی قبل از رندر تصویر رزرو شود.
- رزرو فضا برای محتوای دینامیک: برای بنر تبلیغاتی که بعداً بارگذاری میشود، یک کانتینر با
min-heightمشخص میکنیم.
.ad-banner-container {
min-height: 250px; /* The expected height of the ad */
width: 100%;
background-color: #f0f0f0; /* Optional placeholder color */
}
- بهینهسازی بارگذاری فونت: با افزودن
font-display: swap;به تعریف@font-face، به مرورگر میگوییم که تا زمان بارگذاری فونت سفارشی، از یک فونت سیستمی جایگزین استفاده کند. این کار FOIT را حذف کرده و شیفت ناشی از آن را به حداقل میرساند.
نتیجه CLS: با این تغییرات، CLS از ۰.۲۸ به ۰.۰۵ کاهش یافت که یک نمره عالی محسوب میشود.
نتایج نهایی: از قرمز به سبز و تأثیر آن بر کسبوکار
بیایید نتایج نهایی مطالعه موردی Core Web Vitals جنگو را مرور کنیم:
| معیار (Metric) | قبل از بهینهسازی | بعد از بهینهسازی | وضعیت |
|---|---|---|---|
| LCP | 4.2s | 1.9s | Good |
| INP | 350ms | 150ms | Good |
| CLS | 0.28 | 0.05 | Good |
Passing CWV فراتر از کسب یک مدال افتخار فنی است. این بهینهسازیها تأثیر مستقیمی بر شاخصهای کلیدی کسبوکار داشتند. در هفتههای پس از اعمال این تغییرات، ما شاهد موارد زیر بودیم:
- کاهش ۱۵ درصدی نرخ پرش (Bounce Rate): کاربران کمتری به دلیل کندی، سایت را ترک کردند.
- افزایش ۸ درصدی نرخ تبدیل (Conversion Rate): تجربه کاربری روانتر منجر به خریدهای بیشتری شد.
- بهبود جایگاه در نتایج جستجو: سیگنال مثبت Page Experience به بهبود رتبه صفحات کلیدی ما در گوگل کمک کرد و به توزیع بهتر PageRank در سایت منجر شد.
جمعبندی
این مطالعه موردی نشان داد که دستیابی به نمرات سبز در Core Web Vitals برای یک سایت جنگویی کاملاً امکانپذیر است و نیازی به بازنویسی کامل پروژه ندارد. موفقیت در این مسیر، حاصل یک رویکرد سیستماتیک و چندوجهی است: شروع با تشخیص دقیق گلوگاهها با ابزارهای حرفهای، و سپس اجرای مجموعهای از بهینهسازیهای هدفمند در لایههای مختلف از دیتابیس و بکاند جنگو گرفته تا مدیریت منابع در فرانتاند. تکنیکهایی مانند کشینگ هوشمند، بهینهسازی کوئری، مدیریت صحیح تصاویر، بارگذاری غیرهمزمان جاوااسکریپت و حفظ پایداری بصری، همگی آجرهای سازنده یک تجربه کاربری سریع و لذتبخش هستند. در نهایت، سرمایهگذاری روی Django performance و Core Web Vitals، سرمایهگذاری مستقیم روی رضایت کاربر و موفقیت بلندمدت کسبوکار در فضای رقابتی آنلاین است. این یک بهینهسازی برای الگوریتم نیست، بلکه بهینهسازی برای انسان است؛ و این همان چیزی است که گوگل به آن پاداش میدهد.
سوالات متداول (FAQ)
۱. سایت من از Django Rest Framework و یک فرانتاند جدا (مثل React) استفاده میکند. آیا این راهکارها کاربرد دارند؟
بله، اما با تفاوتهایی. تمام نکات مربوط به بکاند مانند کاهش TTFB از طریق کشینگ و بهینهسازی کوئریهای دیتابیس مستقیماً روی سرعت پاسخدهی API شما تأثیر میگذارند که بخشی از LCP کلی است. اما مسئولیت پیادهسازی تکنیکهای فرانتاند مانند بهینهسازی تصاویر (با srcset)، preload کردن منابع، defer کردن اسکریپتها و رفع CLS بر عهده تیم فرانتاند و فریمورک مورد استفاده (مثلاً Next.js) خواهد بود.
۲. آیا برای پاس کردن Core Web Vitals حتماً باید از CDN استفاده کنم؟
استفاده از یک شبکه توزیع محتوا (CDN) به شدت توصیه میشود، اما اجباری نیست. یک CDN با سرو کردن فایلهای استاتیک (CSS, JS, Images) از سرورهای نزدیک به کاربر، TTFB و زمان دانلود منابع را به طرز چشمگیری کاهش میدهد. برای یک سایت با مخاطبان جهانی، پاس کردن LCP بدون CDN تقریباً غیرممکن است. برای یک سایت با مخاطبان محلی، امکانپذیر است اما همچنان دشوارتر خواهد بود.
۳. گزارش Google Search Console برای URLهای من “No Data” نمایش میدهد. مشکل چیست؟
این پیام به این معنی است که سایت شما هنوز به اندازه کافی ترافیک از کاربران واقعی کروم دریافت نکرده است تا گوگل بتواند دادههای میدانی (Field Data) را در گزارش Chrome User Experience (CrUX) جمعآوری کند. در این حالت، شما باید به دادههای آزمایشگاهی (Lab Data) از ابزارهایی مانند Google PageSpeed Insights یا Lighthouse در مرورگر کروم خود اتکا کنید. این ابزارها یک شبیهسازی از بارگذاری صفحه انجام داده و نمرات CWV را تخمین میزنند که نقطه شروع بسیار خوبی برای بهینهسازی است.


