مقال

تطبيقات الويب التقدمية (PWAs)

تطبيقات الويب التقدمية (PWAs)

تطبيق الويب التقدمي (PWA) هو تطبيق ويب يستخدم إمكانات المتصفح الحديثة لتقديم تجربة تشبه التطبيق. تتميز تطبيقات PWA بأنها موثوقة وسريعة وجذابة - وتجمع بين الوصول إلى الويب وإمكانيات تطبيقات الهاتف المحمول الأصلية.

5 دقيقة قراءةاللغة: AR العربيةمجاني0 تصفيقات0 تعليقات
التقنيةمقالات هندسيةAppsProgressiveWeb DevelopmentTechnologyEngineering ArticlesPWAs
خيارات القراءة

مقدمة

تطبيق الويب التقدمي (PWA) هو تطبيق ويب يستخدم إمكانات المتصفح الحديثة لتقديم تجربة تشبه التطبيق. تتميز تطبيقات PWA بأنها موثوقة وسريعة وجذابة - وتجمع بين الوصول إلى الويب وإمكانيات تطبيقات الهاتف المحمول الأصلية.

تحل تطبيقات PWA توترًا أساسيًا: يريد المستخدمون التوفر الفوري للويب (بدون تثبيت، قابل للربط، محدث دائمًا) ولكنهم يتوقعون أداء وميزات التطبيقات الأصلية (الدعم دون اتصال بالإنترنت، ودفع الإشعارات، ووجود الشاشة الرئيسية). تقدم PWAs كليهما.


الخصائص الأساسية

تمت صياغة مصطلح "تطبيق الويب التقدمي" بواسطة Alex Russell وFrances Berriman من Google في عام 2015. ويجب أن تستوفي PWA هذه الخصائص العشرة:

# المبدأ لماذا يهم؟
1 تقدمي — يناسب الجميع تدهور رشيق على المتصفحات القديمة
2 ** سريع الاستجابة ** — يناسب أي شاشة سطح المكتب، الجهاز اللوحي، الهاتف المحمول
3 اتصال مستقل — يعمل دون اتصال بالإنترنت التخزين المؤقت لعامل الخدمة
4 يشبه التطبيق — إحساس التطبيق الأصلي بنية شل، والتنقل السلس
5 جديد — محدث دائمًا دورة حياة تحديث عامل الخدمة
6 آمن — يتم تقديمه عبر HTTPS يمنع العبث، مطلوب لعمال الخدمة
7 قابل للاكتشاف — صديق لكبار المسئولين الاقتصاديين تقوم محركات البحث بفهرسة PWAs
8 قابلة لإعادة المشاركة — إشعارات الدفع إعادة جذب المستخدمين مثل التطبيقات الأصلية
9 قابل للتثبيت — أضف إلى الشاشة الرئيسية بيان تطبيق الويب
10 قابل للربط — المشاركة عبر URL لا يوجد متجر التطبيقات المطلوبة

الركائز الثلاث لسلطة المياه الفلسطينية

1. عامل الخدمة – المحرك

عامل الخدمة هو ملف JavaScript يتم تشغيله في الخلفية، بشكل منفصل عن صفحة الويب. وهو يعمل بمثابة وكيل شبكة قابل للبرمجة، حيث يعترض الطلبات ويمكّن الوظائف دون اتصال بالإنترنت، ودفع الإشعارات، ومزامنة الخلفية.

دورة حياة عامل الخدمة

Installing → Installed → Activating → Activated → Idle → Terminated
                 │                                        │
                 └─── (new version detected) ──────────────┘
                 └─── Waiting (until all tabs close) ─────┘
// service-worker.js
const CACHE_NAME = 'my-pwa-v2';
const ASSETS_TO_CACHE = [
  '/',
  '/index.html',
  '/styles.css',
  '/app.js',
  '/offline.html',
  '/icons/icon-192.png'
];

// Install event — cache static assets
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      console.log('Caching app shell');
      return cache.addAll(ASSETS_TO_CACHE);
    })
  );
  // Force new service worker to activate immediately
  self.skipWaiting();
});

// Activate event — clean old caches
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames
          .filter(name => name !== CACHE_NAME)
          .map(name => caches.delete(name))
      );
    })
  );
  // Take control of all open pages immediately
  clients.claim();
});

// Fetch event — intercept network requests
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
      // Return cached response if available
      if (cachedResponse) {
        return cachedResponse;
      }

      // Otherwise fetch from network
      return fetch(event.request).then(networkResponse => {
        // Don't cache non-GET or error responses
        if (!event.request.url.includes('/api/')) {
          return networkResponse;
        }

        // Cache API responses for offline use
        const responseClone = networkResponse.clone();
        caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, responseClone);
        });

        return networkResponse;
      }).catch(() => {
        // Network failed — return offline fallback
        if (event.request.mode === 'navigate') {
          return caches.match('/offline.html');
        }
        return new Response('Offline', { status: 503 });
      });
    })
  );
});

استراتيجيات التخزين المؤقت

استراتيجية الوصف حالة الاستخدام
** ذاكرة التخزين المؤقت أولا ** تحقق من ذاكرة التخزين المؤقت، وارجع إلى الشبكة الأصول الثابتة (CSS، JS، الصور)
الشبكة أولا حاول الشبكة، والعودة إلى ذاكرة التخزين المؤقت مكالمات API، المحتوى الديناميكي
** قديمة أثناء إعادة التحقق ** إرجاع ذاكرة التخزين المؤقت والتحديث في الخلفية خلاصات الأخبار، ومنشورات المدونة
الشبكة فقط جلب دائما من الشبكة البيانات الحساسة (المصرفية)
** ذاكرة التخزين المؤقت فقط ** لا يتم الجلب أبدًا من الشبكة قذيفة التطبيق
// Stale-while-revalidate strategy
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
      const fetchPromise = fetch(event.request).then(networkResponse => {
        caches.open(CACHE_NAME).then(cache => {
          cache.put(event.request, networkResponse.clone());
        });
        return networkResponse;
      }).catch(() => cachedResponse);

      return cachedResponse || fetchPromise;
    })
  );
});

2. بيان تطبيق الويب - الهوية

البيان عبارة عن ملف JSON يتحكم في كيفية ظهور PWA عند تثبيته:

{
  "name": "My Progressive Web App",
  "short_name": "MyPWA",
  "description": "An amazing PWA that works offline",
  "start_url": "/?source=pwa",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#3367D6",
  "orientation": "portrait-primary",
  "scope": "/",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ],
  "categories": ["productivity", "utilities"],
  "lang": "en-US",
  "dir": "ltr",
  "prefer_related_applications": false
}

وأوضح الخصائص الظاهرة:

  • العرض: مستقل - يفتح بدون واجهة مستخدم المتصفح (شريط العناوين، علامات التبويب).
  • العرض: ملء الشاشة - ملء الشاشة، بدون متصفح Chrome على الإطلاق.
  • العرض: الحد الأدنى من واجهة المستخدم - الحد الأدنى من عناصر التحكم في المتصفح.
  • النطاق: "/" — ما هي عناوين URL التي تعد جزءًا من PWA.
  • start_url — الصفحة التي يتم فتحها عند تشغيل PWA.
  • أيقونات قابلة للإخفاء — أيقونات قابلة للتكيف تعمل مع الإخفاء على مستوى نظام التشغيل (مستدير، دائري، وما إلى ذلك).

3. HTTPS – المؤسسة

يحتاج عمال الخدمة إلى سياق آمن. HTTPS إلزامي من أجل:

  • تسجيل عمال الخدمة.
  • دفع الإخطارات.
  • مطالبة التثبيت (قبل حدث التنزيل).
# Redirect HTTP to HTTPS
# Nginx
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

بناء PWA – خطوة بخطوة

1. قم بإنشاء App Shell

غلاف التطبيق هو الحد الأدنى من HTML وCSS وJavaScript المطلوب لعرض واجهة المستخدم. يتم تخزينه مؤقتًا عند التحميل الأول ويعمل كأساس لـ PWA.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="theme-color" content="#3367D6">
  <link rel="manifest" href="/manifest.json">
  <link rel="icon" href="/icons/icon-192.png" sizes="192x192">
  <link rel="apple-touch-icon" href="/icons/icon-192.png">
  <title>My PWA</title>
  <link rel="stylesheet" href="/styles.css">
</head>
<body>
  <header id="app-header">My PWA</header>
  <main id="app-content"></main>
  <footer id="app-footer">© 2026</footer>

  <!-- Register service worker -->
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js')
          .then(reg => console.log('SW registered:', reg.scope))
          .catch(err => console.error('SW registration failed:', err));
      });
    }
  </script>
  <script src="/app.js"></script>
</body>
</html>

2. تنفيذ الدعم دون اتصال بالإنترنت

// app.js — Fetch content with offline support
const CACHE_KEY = 'content-cache';

async function loadContent(url) {
  try {
    const response = await fetch(url);
    const data = await response.json();

    // Cache for offline
    const cache = await caches.open(CACHE_KEY);
    cache.put(url, new Response(JSON.stringify(data)));

    renderContent(data);
  } catch (error) {
    // Offline — load from cache
    const cached = await caches.match(url);
    if (cached) {
      const data = await cached.json();
      renderContent(data);
      showOfflineIndicator();
    } else {
      showOfflineMessage();
    }
  }
}

3. أضف إشعارات الدفع

// Request permission
async function requestNotificationPermission() {
  const permission = await Notification.requestPermission();
  if (permission === 'granted') {
    // Get push subscription
    const registration = await navigator.serviceWorker.ready;
    const subscription = await registration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: urlBase64ToUint8Array(publicKey)
    });

    // Send subscription to server
    await fetch('/api/push/subscribe', {
      method: 'POST',
      body: JSON.stringify(subscription)
    });
  }
}
// service-worker.js — Handle push events
self.addEventListener('push', event => {
  const data = event.data.json();

  const options = {
    body: data.body,
    icon: '/icons/icon-192.png',
    badge: '/icons/badge-72.png',
    vibrate: [100, 50, 100],
    data: { url: data.url },
    actions: [
      { action: 'open', title: 'Open' },
      { action: 'close', title: 'Dismiss' }
    ]
  };

  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

self.addEventListener('notificationclick', event => {
  event.notification.close();

  if (event.action === 'open' || !event.action) {
    clients.openWindow(event.notification.data.url);
  }
});

PWA مقابل التطبيق الأصلي

ميزة PWA التطبيق الأصلي
التوزيع عنوان URL (لا يلزم وجود متجر) متجر التطبيقات، جوجل بلاي
** تثبيت الاحتكاك ** نقرة واحدة (موجه المتصفح) تنزيل وتثبيت والأذونات
حجم الملف كيلو بايت إلى ميغابايت من 10 ميجابايت إلى 500 ميجابايت+
** التحديثات ** فوري (عامل الخدمة) عبر مراجعة متجر التطبيقات
** غير متصل ** نعم (عامل الخدمة) نعم (مدمج)
** دفع الإخطارات ** نعم نعم
واجهات برمجة التطبيقات الخاصة بالجهاز الكاميرا، GPS، التسارع، الدفع الوصول الكامل إلى جميع واجهات برمجة التطبيقات الخاصة بالجهاز
بلوتوث بلوتوث الويب (محدود) واجهة برمجة تطبيقات بلوتوث كاملة
** مهام الخلفية ** مزامنة الخلفية (محدودة) تنفيذ الخلفية الكاملة
الأداء شبه أصلي (JavaScript/WebAssembly) أصلي (الكود المترجم)
** تحسين محركات البحث ** قابلة للفهرسة بواسطة محركات البحث غير قابلة للفهرسة
** تكلفة التطوير ** قاعدة تعليمات برمجية واحدة iOS + Android (أو عبر الأنظمة الأساسية)
الاحتفاظ بالمستخدمين أقل (أسهل للمغادرة) أعلى (مثبت = ملتزم)

متى تختار PWA على Native

  • التطبيقات التي تركز على المحتوى — الأخبار والمدونات والمجلات.
  • التجارة الإلكترونية — مواقع التسوق (Pinterest PWA: قضاء وقت إضافي بنسبة 40%).
  • تطبيقات المرافق — الآلات الحاسبة والمحولات والطقس.
  • التطبيقات منخفضة التفاعل — التطبيقات التي يزورها المستخدمون بشكل غير متكرر.
  • الأسواق الناشئة — المستخدمون الذين لديهم مساحة تخزين وبيانات محدودة.
  • التحسين التدريجي — تجربة كاملة على الأجهزة الحديثة، وتعمل على الأجهزة القديمة.

عندما يكون التطبيق الأصلي أفضل

  • ألعاب عالية الأداء — أكثر من 60 إطارًا في الثانية، وعرض ثلاثي الأبعاد معقد.
  • تكامل عميق للأجهزة — الأجهزة الطرفية التي تعمل بتقنية Bluetooth، وNFC، وARKit/ARCore.
  • معالجة الخلفية — بث الموسيقى وتتبع اللياقة البدنية.
  • ** مطلوب تفاعل كبير من قبل المستخدمين ** — وسائل التواصل الاجتماعي، والرسائل.

معايير الأداء

متري قبل سلطة المياه الفلسطينية بعد سلطة المياه الفلسطينية تحسين
التحميل الأول 5s 1.2 ثانية أسرع بنسبة 76%
الأحمال اللاحقة 3ث 0.3 ثانية أسرع بنسبة 90%
** معدل الارتداد ** 45% 20% تخفيض 55%
معدل التحويل 2% 3.5% زيادة 75%
الصفحات لكل جلسة 3 5 زيادة 66%

نتائج العالم الحقيقي:

الشركة المقياس الرئيسي تحسين
تويتر (X) لايت التغريدات المرسلة لكل جلسة زيادة 75%
بينتريست الوقت الذي يقضيه زيادة 40%
اوبر إتمام الحجز سلس حتى على 2G
ستاربكس المستخدمين النشطين يوميا زيادة 2x
علي بابا معدل التحويل زيادة 76%

اختبار وتدقيق PWA

تدقيق Lighthouse PWA

# Run Lighthouse from CLI
npx lighthouse https://example.com --view --preset=desktop

# PWA-specific checks:
# - ✅ Registers a service worker
# - ✅ Responds with 200 when offline
# - ✅ Web app manifest exists
# - ✅ Manifest has display: standalone
# - ✅ Served over HTTPS
# - ✅ Redirects HTTP to HTTPS
# - ✅ Configurable start URL
# - ✅ Icons provided (192px and 512px)

قائمة التحقق من الاختبار اليدوي

## PWA Pre-Flight Checklist
- [ ] HTTPS enabled
- [ ] Service worker registered and active
- [ ] Pages load offline (test with airplane mode)
- [ ] Manifest configured with correct icons
- [ ] "Add to Home Screen" prompt appears
- [ ] PWA opens in standalone mode with no address bar
- [ ] Splash screen displays correctly
- [ ] Push notifications work
- [ ] All pages are responsive (mobile, tablet, desktop)
- [ ] Performance budget met (Lighthouse score > 90)
- [ ] Cross-browser tested (Chrome, Firefox, Safari, Edge)
- [ ] Accessibility audit passes

ميزات PWA المتقدمة

مزامنة الخلفية

// Register a sync event
async function scheduleSync() {
  const registration = await navigator.serviceWorker.ready;
  await registration.sync.register('sync-pending-data');
}

// Service worker handles sync
self.addEventListener('sync', event => {
  if (event.tag === 'sync-pending-data') {
    event.waitUntil(syncPendingData());
  }
});

مزامنة الخلفية الدورية

// Request periodic sync (requires user engagement)
const registration = await navigator.serviceWorker.ready;
await registration.periodicSync.register('update-content', {
  minInterval: 24 * 60 * 60 * 1000 // Once per day
});

واجهة برمجة تطبيقات مشاركة الويب

// Share content using native share sheet
async function shareContent(title, text, url) {
  if (navigator.share) {
    await navigator.share({ title, text, url });
  } else {
    // Fallback to custom share UI
    copyToClipboard(url);
  }
}

واجهة برمجة تطبيقات الشارة

// Set app icon badge
if (navigator.setAppBadge) {
  await navigator.setAppBadge(5); // Show "5" on icon
} else if (navigator.clearAppBadge) {
  await navigator.clearAppBadge();
}

المزالق المشتركة

مأزق مشكلة الحل
** الإفراط في التخزين المؤقت ** يقدم التطبيق محتوى قديمًا ذاكرة التخزين المؤقت للإصدار، قم بتنفيذ ذاكرة التخزين المؤقت أولاً لـ Shell، والشبكة أولاً للمحتوى
** لا يوجد احتياطي دون اتصال ** شاشة بيضاء حاليا قم دائمًا بتخزين /offline.html برسالة ذات معنى
** فشل خرق ذاكرة التخزين المؤقت ** عامل الخدمة القديم لا يزال قائما استخدم SkipWaiting() وclients.claim()
** مشاكل شاشة البداية ** لون أو رمز المظهر خاطئ قم بتكوين البيان بشكل صحيح، واستخدم الرموز القابلة للإخفاء
** التوافق مع رحلات السفاري ** بعض الميزات محدودة (الدفع، المزامنة الدورية) التحسين التدريجي — التحلل برشاقة
حجم ذاكرة التخزين المؤقت كبير تم تجاوز حصة التخزين (50 ميجابايت لكل أصل) تقليم ذاكرة التخزين المؤقت القديمة، والحد من حجم ذاكرة التخزين المؤقت
start_url مفقود تفتح الشاشة الرئيسية صفحة خاطئة حدد دائمًا start_url في البيان

الاستنتاج

تمثل تطبيقات الويب التقدمية أفضل ما في العالمين - الوصول إلى الويب وإمكانية الوصول إليه بالإضافة إلى الإمكانات وتجربة المستخدم للتطبيقات الأصلية.

متى يتم بناء PWA

  1. تريد أقصى قدر من الوصول — تطبيق واحد لجميع الأنظمة الأساسية.
  2. ** يحتاج المستخدم إلى الوصول دون اتصال بالإنترنت ** — التخزين المؤقت لعامل الخدمة.
  3. تريد التحميل الفوري — بنية غلاف التطبيق.
  4. تريد إعادة المشاركة — دفع الإشعارات بدون متجر التطبيقات.
  5. لديك تطبيق يعتمد على المحتوى — الأخبار، والتجارة الإلكترونية، والمرافق.

البدء

  1. أضف Manifest.json والأيقونات.
  2. قم بإنشاء عامل خدمة مع إمكانية الرجوع دون اتصال بالإنترنت.
  3. قم بإجراء تدقيق Lighthouse وأصلح المشكلات الحرجة.
  4. اختبار على الأجهزة الحقيقية (Android، iOS، سطح المكتب).
  5. نشر وقياس تفاعل المستخدم.

لا تعد تطبيقات PWA بديلاً للتطبيقات الأصلية في كل السيناريوهات - ولكن بالنسبة لمعظم التطبيقات المستندة إلى المحتوى والتطبيقات المساعدة، فإنها توفر تجربة مستخدم فائقة مع جزء صغير من تكلفة التطوير.

مقالات مختارة

50 مهارة من Claude تستحق البناء في 2026
تحريريAR
10 دمجاني

50 مهارة من Claude تستحق البناء في 2026

التقنيةAIAi GuidesAI Agents
0 تصفيقات
قراءة
ابن مساعد ملاحظات خاص بالذكاء الاصطناعي
مميزAR
9 دمجاني

ابن مساعد ملاحظات خاص بالذكاء الاصطناعي

حوّل مجلد ملاحظات Markdown إلى مساعد بحث دون كشف المسودات الخاصة.

التقنيةأدلة المنصةالكتابة بالذكاء الاصطناعيAIAutomationData
0 تصفيقات
قراءة
أتمتة استخراج بيانات الفواتير باستخدام OCR
تحريريAR
8 دمجاني

أتمتة استخراج بيانات الفواتير باستخدام OCR

ابن خط معالجة يقرأ الفواتير ويستخرج الحقول ويعلّم القيم غير المؤكدة للمراجعة.

التقنيةمقالات هندسيةالكتابة بالذكاء الاصطناعيAIAutomationData
0 تصفيقات
قراءة

التعليقات

0 تعليقات

لا توجد تعليقات معتمدة بعد. قد تنتظر الردود الجديدة المراجعة.