عمال الخدمة: وكيل الشبكة القابل للبرمجة
تحويل موقع الويب الخاص بك إلى تطبيق غير متصل بالشبكة. دليل فني لدورة حياة عامل الخدمة، واستراتيجيات التخزين المؤقت (مربع العمل)، والمزامنة في الخلفية.
الفرق الأكبر بين التطبيق الأصلي وتطبيق الويب هو المرونة. إذا قمت بفتح Instagram في وضع الطائرة، فسترى الصور المخزنة مؤقتًا. إذا قمت بفتح موقع ويب قياسي في وضع الطائرة، فسترى الديناصور.
وهذا أمر غير مقبول بالنسبة للبرامج الحديثة. عمال الخدمة هم الحل. وهي عبارة عن برنامج نصي عامل لجافا سكريبت يتم تشغيله في الخلفية، بشكل منفصل عن صفحة الويب. إنهم بمثابة ** وكيل الشبكة من جانب العميل **.
في Maison Code Paris، نقوم ببناء تطبيقات الويب التقدمية (PWAs) التي تجتاز “اختبار Subway”: هل يمكن للمستخدم تصفح الكتالوج أثناء وجوده تحت الأرض؟ إذا كانت الإجابة لا، فإن التطبيق معطل.
لماذا تتحدث Maison Code عن هذا
في Maison Code Paris، نعمل كضمير معمari لعملائنا. غالبًا ما نرث حزمًا “حديثة” تم بناؤها دون فهم أساسي للحجم.
نناقش هذا الموضوع لأنه يمثل نقطة تحول حاسمة في النضج الهندسي. التنفيذ الصحيح يميز MVP الهش عن منصة مؤسسية مرنة يمكنها التعامل مع حركة مرور الجمعة السوداء.
لماذا يتطلب قانون ميزون عدم الاتصال بالإنترنت أولاً
الشاشة البيضاء هي عميل ضائع. نحن نتعامل مع “غير متصل” كميزة، وليس كحالة خطأ. يضمن معيار PWA الخاص بنا ما يلي:
- المرونة: يتم تحميل غلاف التطبيق على الفور، حتى على شبكة الجيل الثاني.
- المشاركة: يمكن للمستخدمين الإضافة إلى سلة التسوق أثناء عدم الاتصال بالإنترنت (ترسلها ميزة مزامنة الخلفية لاحقًا).
- الاحتفاظ: تحقق الإشعارات الفورية معدل إرجاع أعلى بمقدار 3 أضعاف من البريد الإلكتروني لعملائنا الذين يستخدمون الهاتف المحمول أولاً. نحن لا نبني “مواقع الويب”؛ نحن نبني “تطبيقات الويب القابلة للتثبيت”.
النموذج العقلي: الرجل في الوسط
عادةً: “المتصفح -> الشبكة -> الخادم”. باستخدام SW: “المتصفح -> عامل الخدمة”. ثم يقرر عامل الخدمة ما يلي:
- “لدي هذا في ذاكرة التخزين المؤقت. قم بإرجاع ذاكرة التخزين المؤقت.” (زمن الوصول 0 مللي ثانية).
- “أحتاج للذهاب إلى الشبكة.” (الكمون القياسي).
- “انتقل إلى الشبكة، ولكن إذا فشلت، قم بإرجاع ذاكرة التخزين المؤقت.” (المرونة).
هذا المنطق قابل للبرمجة. يمكنك التحكم في كل بايت.
دورة الحياة (الجزء الصعب)
من المعروف أن عمال الخدمة يصعب تصحيحهم لأنهم يعيشون بشكل مستقل عن علامة التبويب.
- التثبيت: يقوم المتصفح بتنزيل sw.js. يقوم بتنزيل الأصول المهمة (Precache).
- التنشيط: يبدأ تشغيل البرنامج. يقوم بتنظيف المخابئ القديمة. الأهم من ذلك أنه لا يتحكم في علامات التبويب المفتوحة بعد.
- المطالبة: يجب عليك الاتصال بـ
clients.claim()للتحكم في علامات التبويب المفتوحة على الفور. - الجلب: يقوم برنامج SW بإنشاء مستمع حدث
fetch.
مشكلة “الإصدار الجديد”.
قمت بنشر “الإصدار 2”. موقع زيارات المستخدم.
يرى المتصفح أن sw.js قد تغير. يقوم بتثبيت “v2” في الخلفية.
لكن v1 لا يزال يشغل الصفحة!
يدخل v2 في حالة “الانتظار”.
سيتم تفعيله فقط عندما تكون جميع علامات التبويب مغلقة.
لإصلاح هذه المشكلة، نقوم بتطبيق نخب “التحديث متوفر” في واجهة المستخدم.
// في تطبيق React الخاص بك
إذا (التسجيل.انتظار) {
showToast("التحديث متاح"، () => {
Registration.waiting.postMessage({ النوع: 'SKIP_WAITING' });
window.location.reload();
});
}
استراتيجيات التخزين المؤقت (باستخدام Workbox)
كتابة منطق التخزين المؤقت الخام عرضة للخطأ. نحن نستخدم Google Workbox.
1. ذاكرة التخزين المؤقت المسبقة (غطاء التطبيق)
نقوم بتنزيل هيكل HTML والشعار وحزمة JS الرئيسية أثناء التثبيت. يتم “تثبيت” هذه الملفات في ذاكرة التخزين المؤقت. ويضمن لهم أن يكونوا هناك.
استيراد { precacheAndRoute } من 'workbox-precaching'؛
// يتم إدخال __WB_MANIFEST بواسطة أداة الإنشاء (Webpack/Vite)
precacheAndRoute(self.__WB_MANIFEST);
2. قديمة أثناء إعادة التحقق (المحتوى الديناميكي)
بالنسبة لاستدعاءات واجهة برمجة التطبيقات (/api/products)، نريد السرعة ولكن أيضًا الحداثة.
- الخطوة 1: قم بإرجاع JSON المخزن مؤقتًا على الفور. (يتم عرض التطبيق في 50 مللي ثانية).
- الخطوة 2: جلب JSON جديد من الشبكة.
- الخطوة 3: تحديث ذاكرة التخزين المؤقت.
- الخطوة 4: تحديث البث لواجهة المستخدم (“الأسعار الجديدة متاحة”).
استيراد { سجل الطريق } من 'توجيه مربع العمل'؛
استيراد { StaleWhileRevalidate } من "استراتيجيات صندوق العمل"؛
طريق التسجيل(
({ url }) => url.pathname.startsWith('/api/'),
جديد StaleWhileRevalidate({
اسم ذاكرة التخزين المؤقت: "ذاكرة التخزين المؤقت لواجهة برمجة التطبيقات"،
الإضافات: [
new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 3600 }), // احتفظ به لمدة ساعة واحدة
]،
})
);
3. ذاكرة التخزين المؤقت أولاً (الأصول غير القابلة للتغيير)
بالنسبة لصور المنتج (التي تتم استضافتها على شبكات CDN ذات عناوين URL ذات إصدار)، نستخدم Cache First. إذا كان في ذاكرة التخزين المؤقت، قم بإعادته. لا تصل أبدا إلى الشبكة.
التخزين دون اتصال: IndexedDB
“التخزين المحلي” متزامن. إنه يمنع الخيط الرئيسي. عمال الخدمة غير متزامنين. إنهم ** لا يمكنهم الوصول إلى LocalStorage **. يجب عليك استخدام IndexedDB. إنها قاعدة بيانات NoSQL داخل المتصفح. نستخدمه لتخزين “الإجراءات المعلقة”.
السيناريو: ينقر المستخدم على “إضافة إلى سلة التسوق” أثناء عدم الاتصال بالإنترنت.
- يكتشف التطبيق عدم الاتصال بالإنترنت.
- يكتب التطبيق الإجراء إلى IndexedDB:
{ type: 'ADD_TO_CART', id: 123 }. - يقوم التطبيق بتحديث واجهة المستخدم بشكل متفائل (تظهر الشارة “1”).
- يقوم عامل الخدمة بتسجيل حدث مزامنة الخلفية.
مزامنة الخلفية
هذه هي الميزة القاتلة. عندما يعود الاتصال (حتى لو أغلق المستخدم التطبيق!)، يقوم نظام التشغيل بتنشيط عامل الخدمة.
// sw.js
self.addEventListener('sync', (event) => {
إذا (event.tag === "عربة المزامنة") {
events.waitUntil(syncCart());
}
});
وظيفة غير متزامنة syncCart () {
const db = انتظار openDB('my-store');
إجراء ثابت = انتظار db.get('pending', 'cart');
انتظار الجلب('/api/cart', { الطريقة: 'POST', الجسم: JSON.stringify(action) });
}
المزالق الشائعة
- التخزين المؤقت لعامل الخدمة نفسه: تأكد من أن خادمك يرسل “Cache-Control: no-cache” لـ “sw.js”. إذا قام المتصفح بتخزين ملف SW مؤقتًا لمدة 24 ساعة، فلن تتمكن من نشر التحديثات لمدة 24 ساعة.
- الاستجابات غير الشفافة (CORS):
إذا قمت بإحضار صورة من
cdn.shopify.comبدون رؤوس CORS، فسيرى برنامج SW “استجابة غير شفافة”. لا يمكن التحقق من رمز الحالة. قد يقوم بتخزين صفحة خطأ 404 كصورة. قم دائمًا بتكوين CORS على مجموعاتك. - تم تجاوز الحصة: تحدد المتصفحات سعة التخزين (عادةً 10-20% من مساحة القرص). قم دائمًا بتنفيذ سياسات الإخلاء الأقل استخدامًا (LRU) (باستخدام البرنامج الإضافي Workbox Expiration Plugin).
10. مزامنة الخلفية الدورية
تعمل المزامنة القياسية عند عودة الاتصال.
المزامنة الدورية تسمح للتطبيق بالتنشيط في الخلفية (على سبيل المثال، مرة واحدة كل 24 ساعة) لجلب محتوى جديد.
تخيل تطبيق أخبار. تريد أن يحصل المستخدم على عناوين الأخبار الصباحية قبل أن يفتح التطبيق.
registration.periodicSync.register('get-headlines', { minInterval: 24 * 60 * 60 * 1000 });.
ملاحظة: يتطلب هذا عادةً تثبيت PWA على الشاشة الرئيسية.
11. نصائح لتصحيح الأخطاء (Chrome DevTools)
علامة التبويب “التطبيق” في Chrome هي أفضل صديق لك.
- التحديث عند إعادة التحميل: حدد هذا المربع أثناء التطوير. إنه يفرض على المتصفح تجاوز ذاكرة التخزين المؤقت SW لملف SW نفسه.
- إلغاء التسجيل: الخيار النووي. إذا كانت الأمور غريبة، قم بإلغاء تسجيل البرنامج للبدء من جديد.
- تخزين ذاكرة التخزين المؤقت: اعرض بالضبط ما تم حفظه من كائنات JSON الثنائية الكبيرة. إذا كانت
api-cacheفارغة، فهذا يعني أن مُطابق Regex لديك خاطئ.
13. تشفير الحمولة النافعة للإشعارات
يتم تشفير Web Push (AES-128-GCM).
يقوم المتصفح بإنشاء زوج مفاتيح عام/خاص.
يجب أن يقوم الخادم (VAPID) بتشفير الحمولة باستخدام المفتاح العام للمتصفح.
إذا قمت بإرسال JSON عادي، فسيرفضه المتصفح.
يتلقى عامل الخدمة حدث “الدفع”، ويفك تشفيره (يتم التعامل معه بواسطة نظام تشغيل المتصفح)، ويعرض الإشعار.
self.registration.showNotification(data.title, { body: data.body, icon: '/icon.png' }).
انتظر حتى يتم حل الوعد (event.waitUntil) لضمان ظهور الإشعار حتى لو تم قتل البرنامج على الفور.
14. وحدات صندوق العمل: استخدم النظام الأساسي
لا تعيد اختراع العجلة.
“التخزين المؤقت لصندوق العمل”، “توجيه صندوق العمل”، “استراتيجيات صندوق العمل”، “انتهاء صلاحية صندوق العمل”.
نستخدم أيضًا “workbox-window” في الموضوع الرئيسي للتواصل مع SW.
const wb = new Workbox('/sw.js'); wb.addEventListener('installed', ...).
يؤدي هذا إلى تجريد واجهة برمجة التطبيقات “navigator.serviceWorker” المعقدة ويتعامل مع مراوغات المتصفح (Safari).
15. تاريخ الويب غير المتصل بالإنترنت (AppCache)
قبل عمال الخدمة، كان لدينا AppCache. تم تعريفه في ثلاث كلمات: “AppCache عبارة عن Douchebag”. لقد كان تصريحيًا وصارمًا وكسر كل شيء. إذا قمت بتغيير بايت واحد في البيان، فسيقوم المتصفح بتنزيل كل شيء مرة أخرى. استبدله عمال الخدمة بواجهة برمجة تطبيقات ضرورية. تكتب الكود. عليك أن تقرر ما يجب القيام به. هذا التحول من التكوين إلى التعليمات البرمجية هو سبب نجاح عمال الخدمة حيث فشل AppCache.
16. عقبات سفاري (iOS)
لدى Apple علاقة حب وكراهية مع PWAs. إنهم يدعمون عمال الخدمة، ولكن:
- التخزين: يقومون بحذف البيانات إذا لم يتم استخدامها لمدة 7 أيام (ITP).
- الدفع: مدعوم فقط في نظام التشغيل iOS 16.4+ (ويجب على المستخدم إضافته إلى الشاشة الرئيسية).
- المزامنة: مزامنة الخلفية محدودة للغاية. نحن نبني تطبيقات “تقدمية”. المعنى: أنها تعمل بشكل مثالي على Chrome. إنها تتحلل بشكل جيد على Safari (تعود إلى الشبكة فقط في حالة فشل برنامج SW).
17. الاستنتاج
عامل الخدمة لا يقتصر على “غير المتصل” فقط. إنها أداة الأداء. فهو يفصل وقت بدء التطبيق عن جودة الشبكة. في اتصال 4G غير المستقر، يُحدث عامل الخدمة الفرق بين الارتداد والبيع.
في Maison Code، نتعامل مع الشبكة باعتبارها “بنية تحتية غير موثوقة” ونضفي المرونة على العميل.
**[قم بتوظيف مهندسينا](/contact)**.