تطبيقات الويب التقدمية
أساسيات Service Workers
ما هي Service Workers؟
Service Workers هي ملفات JavaScript تعمل بشكل منفصل عن مسار المتصفح الرئيسي، وتعمل كوكيل شبكة قابل للبرمجة. تعترض طلبات الشبكة، وتخزن الموارد مؤقتاً، وتمكّن وظائف العمل بدون إنترنت، مما يجعلها العمود الفقري لتطبيقات الويب التقدمية.
الخصائص الرئيسية:
- تعمل في الخلفية: منفصلة عن صفحات الويب، لا يمكنها الوصول لـ DOM مباشرة
- مدفوعة بالأحداث: تستجيب للأحداث (install, activate, fetch, push, sync)
- ذاكرة تخزين مؤقت قابلة للبرمجة: تحكم كامل في استراتيجيات التخزين المؤقت
- HTTPS مطلوب: يجب تقديمها عبر اتصال آمن (باستثناء localhost)
- قائمة على النطاق: تتحكم في الصفحات ضمن مسار نطاقها
- دورة حياة مُدارة: مراحل التثبيت والتفعيل والتحديث
قدرات Service Worker
ما يمكن لـ Service Workers فعله:
✓ اعتراض ومعالجة طلبات الشبكة
✓ تخزين الموارد مؤقتاً (HTML, CSS, JS, الصور، استجابات API)
✓ تمكين وظائف العمل بدون إنترنت
✓ المزامنة في الخلفية (إعادة محاولة الطلبات الفاشلة)
✓ إشعارات الدفع
✓ إدارة ذاكرات تخزين مؤقت متعددة
✓ تحديث المحتوى المخزن مؤقتاً بذكاء
ما لا يمكن لـ Service Workers فعله:
✗ الوصول لـ DOM مباشرة
✗ استخدام APIs متزامنة (localStorage)
✗ الوصول للكوكيز مباشرة (استخدم fetch مع credentials)
✗ العمل بدون التسجيل من صفحة
دورة حياة Service Worker
دورة الحياة الكاملة:
- التسجيل: الصفحة تسجل ملف service worker
- التثبيت: service worker يُحمّل ويُثبّت (يحدث مرة واحدة)
- التفعيل: service worker يأخذ السيطرة (يحدث بعد التثبيت)
- الخمول: ينتظر الأحداث (fetch, push, sync)
- معالجة Fetch/الأحداث: يستجيب لطلبات الشبكة والأحداث
- الإنهاء: المتصفح يمكنه إيقاف service workers الخاملة لتوفير الذاكرة
- التحديث: إصدار جديد يشغل دورة install/activate جديدة
مخطط دورة حياة Service Worker
┌─────────────────┐
│ تحميل الصفحة │
│ تسجيل SW │
└────────┬────────┘
│
▼
┌─────────────────┐
│ التثبيت │ ← المرة الأولى فقط
│ (حدث install) │ تخزين الأصول الثابتة
└────────┬────────┘
│
▼
┌─────────────────┐
│ مُثبّت │
│ (انتظار) │ ← ينتظر توقف SW القديم
└────────┬────────┘
│
▼
┌─────────────────┐
│ التفعيل │
│ (حدث activate) │ ← تنظيف ذاكرة التخزين القديمة
└────────┬────────┘
│
▼
┌─────────────────┐
│ مُفعّل │
│ (خامل) │ ← يتحكم في الصفحات في النطاق
└────────┬────────┘
│
▼
┌─────────────────┐
│ FETCH/الأحداث │ ← يعترض الطلبات
│ (حدث fetch) │ يتعامل مع push, sync
└─────────────────┘
دعم المتصفحات
| المتصفح | الدعم | منذ الإصدار |
|---|---|---|
| Chrome | ✓ دعم كامل | v40 (2015) |
| Firefox | ✓ دعم كامل | v44 (2016) |
| Safari | ✓ دعم كامل | v11.1 (2018) |
| Edge | ✓ دعم كامل | v17 (2018) |
| Opera | ✓ دعم كامل | v27 (2015) |
| Samsung Internet | ✓ دعم كامل | v4 (2016) |
فحص دعم المتصفح:
if ('serviceWorker' in navigator) {
console.log('Service Worker مدعوم!');
} else {
console.log('Service Worker غير مدعوم');
}
متطلب HTTPS
متطلب الأمان:
يجب تقديم Service Workers عبر HTTPS في الإنتاج لأنها يمكنها اعتراض طلبات الشبكة وتعديل الاستجابات. هذا يمنع هجمات man-in-the-middle.
الاستثناءات:localhostو127.0.0.1(للتطوير المحلي)- عناوين الشبكة المحلية (مثل
192.168.x.x) في بعض المتصفحات
- استخدم localhost أثناء التطوير
- استخدم أدوات مثل ngrok لنفق HTTPS
- استخدم Let's Encrypt لشهادات SSL مجانية في الإنتاج
نطاق Service Worker
فهم النطاق:
النطاق يحدد أي الصفحات التي يتحكم فيها service worker. افتراضياً، النطاق هو الدليل الذي يوجد فيه ملف service worker.
// Service worker في: /sw.js
// النطاق الافتراضي: / (الموقع بأكمله)
navigator.serviceWorker.register('/sw.js');
// Service worker في: /app/sw.js
// النطاق الافتراضي: /app/ (فقط الصفحات تحت /app/)
navigator.serviceWorker.register('/app/sw.js');
// نطاق مخصص (يجب أن يكون ضمن دليل service worker أو أعلى)
navigator.serviceWorker.register('/sw.js', {
scope: '/app/' // يتحكم فقط في صفحات /app/*
});
// غير صحيح: لا يمكن التحكم في الصفحات خارج دليل service worker
// Service worker في: /app/sw.js
navigator.serviceWorker.register('/app/sw.js', {
scope: '/' // ✗ خطأ: النطاق خارج مسار service worker
});
أفضل ممارسات النطاق:
- ضع service worker في الجذر (/) للتحكم في الموقع بأكمله
- استخدم نطاق مخصص للتحكم في أقسام معينة
- يمكن لـ service workers متعددة التحكم في نطاقات مختلفة
- النطاقات الأكثر تحديداً لها الأولوية على العامة
تصحيح Service Workers
Chrome DevTools
1. افتح DevTools (F12)
2. انتقل إلى تبويب Application
3. انقر على Service Workers في الشريط الجانبي
يمكنك:
✓ رؤية service workers المسجلة
✓ إلغاء تسجيل service workers
✓ فرض التحديث/تخطي الانتظار
✓ محاكاة وضع عدم الاتصال
✓ عرض مصدر service worker
✓ رؤية workers النشطة/المنتظرة
✓ التحقق من النطاق والحالة
Firefox DevTools
1. افتح DevTools (F12)
2. انتقل إلى تبويب Application (أو about:debugging#/runtime/this-firefox)
3. انقر على Service Workers
خاص بـ Firefox:
✓ رؤية جميع service workers عبر جميع المواقع
✓ تصحيح service workers
✓ بدء/إيقاف service workers
✓ عرض اشتراكات push
Safari DevTools
1. تمكين قائمة Develop (Safari ← Preferences ← Advanced)
2. Develop ← Service Workers
3. اختر موقعك
خاص بـ Safari:
✓ سرد جميع service workers
✓ فحص console الخاص بـ service worker
✓ عرض حالة service worker
أحداث Service Worker
الأحداث الأساسية:
| install | يُطلق عندما يُثبت service worker لأول مرة |
| activate | يُطلق عندما يصبح service worker نشطاً |
| fetch | يُطلق لكل طلب شبكة في النطاق |
| message | الاتصال بين الصفحة وservice worker |
| sync | المزامنة في الخلفية عند استعادة الاتصال |
| push | استلام إشعار دفع |
هيكل Service Worker الأساسي
// sw.js - ملف service worker أساسي
// حدث Install - تخزين الأصول الثابتة
self.addEventListener('install', event => {
console.log('Service Worker: جاري التثبيت...');
// منطق التخزين المؤقت هنا
});
// حدث Activate - تنظيف ذاكرة التخزين القديمة
self.addEventListener('activate', event => {
console.log('Service Worker: مُفعّل');
// منطق التنظيف هنا
});
// حدث Fetch - اعتراض طلبات الشبكة
self.addEventListener('fetch', event => {
console.log('Service Worker: جلب', event.request.url);
// منطق معالجة الطلبات هنا
});
الأخطاء الشائعة:
- عدم التحقق من دعم المتصفح: تحقق دائماً من
if ('serviceWorker' in navigator) - نسيان HTTPS: service workers لن تُسجل على HTTP (باستثناء localhost)
- نطاق خاطئ: service worker لا يمكنها التحكم في الصفحات خارج دليلها
- عدم التحديث: service workers القديمة يمكن أن تبقى نشطة إلى أجل غير مسمى بدون منطق تحديث
- حظر التفعيل: service workers الجديدة تنتظر حتى تُغلق جميع الصفحات التي تستخدم القديمة
- التخزين المؤقت بدون تنظيف: ذاكرة التخزين القديمة تتراكم وتهدر المساحة
مثال دورة حياة Service Worker
// سكريبت الصفحة (main.js)
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW مسجل:', registration.scope);
// تحقق من التحديثات بشكل دوري
registration.update();
// استمع للتحديثات
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
// service worker جديد متاح
console.log('محتوى جديد متاح، يرجى التحديث');
}
});
});
})
.catch(error => {
console.error('فشل تسجيل SW:', error);
});
}
تمرين:
- افتح Chrome DevTools ← Application ← Service Workers
- قم بزيارة PWA (مثل twitter.com أو pinterest.com) وافحص service worker الخاص بها
- تحقق من حالة service worker والنطاق والكود المصدري
- استخدم خانة الاختيار "Offline" لمحاكاة وضع عدم الاتصال
- أعد تحميل الصفحة ولاحظ كيف تعمل بدون إنترنت
- انقر على "Unregister" وأعد التحميل - لاحظ الفرق
- أنشئ صفحة HTML بسيطة وحاول تسجيل service worker أساسي
- افحص دورة حياة service worker في DevTools