بناء تطبيق PWA يعمل أوفلاين باستخدام Next.js وService Workers

PWA Next.js offline: بناء تطبيق يعمل أوفلاين باستخدام Next.js وService Workers

إذا كنت تريد بناء تطبيق ويب يشبه التطبيقات الأصلية (Native) ويعمل حتى بدون اتصال بالإنترنت، فالحل هو Progressive Web App (PWA). ومع إطار مثل Next.js يمكنك دمج الـ PWA بسهولة مع أداء عالٍ وSEO قوي.

في هذا الدليل سنتعلم خطوة بخطوة كيفية بناء PWA Next.js offline باستخدام مكتبة next-pwa وService Workers، مع التركيز على:

  • إعداد Next.js ليعمل كتطبيق PWA.
  • توليد Service Worker وتخزين الموارد أوفلاين.
  • استراتيجيات التخزين المؤقت والتحديث.
  • تحسين تجربة المستخدم على الموبايل.

إذا لم تكن لديك خلفية سابقة عن PWA مع Next.js يمكنك مراجعة مقالنا السابق بناء PWA مع Next.js وNext-PWA كمقدمة أساسية، ثم العودة لهذا الدليل التطبيقي المتقدم.

ما هو PWA ولماذا يهم أن يعمل أوفلاين؟

Progressive Web App (PWA) هو تطبيق ويب يستخدم تقنيات حديثة مثل Service Workers وWeb App Manifest لتقديم تجربة قريبة من تطبيقات الجوال:

  • إمكانية التثبيت على شاشة الهاتف الرئيسية (Add to Home Screen).
  • العمل في وضع أوفلاين أو شبكة ضعيفة.
  • تحميل سريع واستجابة عالية.
  • إشعارات Push (في بعض السيناريوهات).

ميزة العمل أوفلاين في PWA Next.js offline تعتمد أساساً على:

  1. Service Worker: ملف جافاسكربت يعمل في الخلفية ويتحكم في الشبكة والتخزين المؤقت (Cache).
  2. Cache Storage: مكان تخزين الملفات (HTML، CSS، JS، صور) ليتم استخدامها بدون اتصال.
  3. استراتيجيات الجلب (Caching Strategies): طريقة اتخاذ القرار بين الجلب من الشبكة أو الكاش.

لماذا استخدام Next.js لبناء PWA؟

Next.js يوفر مجموعة مزايا تجعله مناسباً لبناء PWA احترافية:

  • Server-Side Rendering (SSR) وStatic Site Generation (SSG) لتحسين SEO وسرعة التحميل الأولي.
  • دعم جاهز لملفات _document.js و_app.js لتخصيص الـ Head والستايلات وتضمين manifest.
  • سهولة الدمج مع next-pwa لتوليد Service Worker تلقائياً.

وبدمج Next.js مع Service Worker بشكل صحيح، تحصل على PWA Next.js offline يعمل بسلاسة حتى في انقطاع الإنترنت.

إعداد مشروع Next.js كأساس لـ PWA

1. إنشاء مشروع Next.js جديد

ابدأ بإنشاء مشروع Next.js (أو استخدم مشروعك الحالي):

npx create-next-app pwa-nextjs-offline
cd pwa-nextjs-offline

أو باستخدام TypeScript:

npx create-next-app@latest pwa-nextjs-offline --typescript
cd pwa-nextjs-offline

2. تثبيت مكتبة next-pwa

بدلاً من كتابة Service Worker يدوياً، سنستخدم next-pwa، وهي مكتبة تسهّل تحويل مشروعك إلى PWA مع خيارات للكاش واستراتيجيات التخزين.

npm install next-pwa
# أو
yarn add next-pwa

ضبط next-pwa لتفعيل PWA والعمل أوفلاين

1. تعديل ملف next.config.js

افتح next.config.js وأضف إعدادات next-pwa. الفكرة أن نُغلّف إعدادات Next.js بمُهيئ withPWA:

const withPWA = require('next-pwa')({
  dest: 'public',
  register: true,
  skipWaiting: true,
  // يمكن تفعيل هذا الخيار لاحقاً لتخصيص الاستراتيجيات
  // runtimeCaching: [...]
})

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
}

module.exports = withPWA(nextConfig)
  • dest: 'public' تعني أن Service Worker وملفات الكاش سيتم إنشاؤها داخل مجلد public.
  • register: true يقوم بتسجيل Service Worker تلقائياً في المتصفح.
  • skipWaiting: true يجعل Service Worker الجديد يحل محل القديم مباشرة بعد التحديث.

2. إضافة ملف manifest.json

ملف manifest.json يعرف معلومات التطبيق مثل الاسم والأيقونات والألوان، ويسمح بالتثبيت على شاشة الهاتف.

أنشئ ملفاً باسم manifest.json داخل مجلد public:

{
  "name": "PWA Next.js Offline Demo",
  "short_name": "PWA Offline",
  "description": "تطبيق PWA Next.js offline يعمل بدون اتصال بالإنترنت.",
  "start_url": "/",
  "display": "standalone",
  "orientation": "portrait",
  "background_color": "#ffffff",
  "theme_color": "#0f172a",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

تأكد من توفير الأيقونات في المسارات المذكورة. يمكنك توليدها من أي لوجو باستخدام أدوات مثل PWABuilder.

3. ربط manifest والأيقونات في _document.js

لإخبار المتصفح بوجود manifest، نضيف روابط داخل عنصر Head الخاص بـ Next.js.

أنشئ أو عدّل ملف pages/_document.js كالتالي:

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
  render() {
    return (
      <Html lang="ar" dir="rtl">
        <Head>
          <link rel="manifest" href="/manifest.json" />
          <meta name="theme-color" content="#0f172a" />
          <link rel="icon" href="/icons/icon-192x192.png" />
          <link rel="apple-touch-icon" href="/icons/icon-192x192.png" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

كيف يعمل Service Worker في PWA Next.js offline؟

عند بناء المشروع في وضع الإنتاج، تقوم next-pwa بتوليد ملف service-worker.js تلقائياً. هذا الملف:

  • يتم تثبيته في المتصفح عند زيارة الموقع لأول مرة.
  • يقوم بتخزين الموارد (HTML، JS، CSS، صور) في Cache Storage.
  • يعترض طلبات الشبكة ويقرر هل يُرجع الموارد من الكاش أو من الإنترنت.

لرؤية Service Worker فعلياً:

  1. قم ببناء المشروع وتشغيله في وضع الإنتاج:
    npm run build
    npm run start
    
  2. افتح المتصفح (Chrome مثلاً) ثم DevTools > Application > Service Workers.
  3. سترى Service Worker مسجلاً على الدومين المحلي مع حالة Activated.

تخزين الموارد أوفلاين: استراتيجيات الكاش

قوة PWA Next.js offline تأتي من استراتيجية التخزين المؤقت للموارد. next-pwa مبنية على workbox وتدعم خيارات متعددة.

1. المفاهيم الأساسية للاستراتيجيات

  • Cache First: جلب من الكاش أولاً، وإذا لم يوجد فالرجوع للشبكة. ممتاز للملفات الثابتة مثل الصور والأيقونات.
  • Network First: محاولة الجلب من الشبكة أولاً، وإذا فشلت (أوفلاين) يتم استخدام الكاش. مناسب لصفحات المحتوى المتغير.
  • Stale While Revalidate: إرجاع نسخة من الكاش فوراً، ثم التحقق من تحديث النسخة في الخلفية.

2. تخصيص runtimeCaching في next-pwa

لضبط كيفية تعامل Service Worker مع طلبات معينة، نستخدم خيار runtimeCaching في next.config.js.

أضف ملفاً باسم next-pwa.config.js في جذر المشروع (اختياري للتنظيم):

const runtimeCaching = [
  {
    // كاش للصفحات (HTML) باستخدام Network First
    urlPattern: /^https?.*/,
    handler: 'NetworkFirst',
    options: {
      cacheName: 'http-pages-cache',
      networkTimeoutSeconds: 10,
      expiration: {
        maxEntries: 50,
        maxAgeSeconds: 24 * 60 * 60, // يوم واحد
      },
      cacheableResponse: {
        statuses: [0, 200],
      },
    },
  },
]

module.exports = runtimeCaching

ثم عدّل next.config.js لاستيراد هذا الإعداد:

const runtimeCaching = require('./next-pwa.config')

const withPWA = require('next-pwa')({
  dest: 'public',
  register: true,
  skipWaiting: true,
  runtimeCaching,
})

const nextConfig = {
  reactStrictMode: true,
}

module.exports = withPWA(nextConfig)

الآن، عند زيارة الموقع مرة على الأقل، يمكن للمستخدم تصفح الصفحات التي تمت زيارتها من قبل حتى في وضع أوفلاين.

مثال عملي: صفحة تعمل أوفلاين مع رسالة مخصصة

لتحسين تجربة المستخدم، من الأفضل تقديم صفحة أوفلاين خاصة بدلاً من رسالة المتصفح الافتراضية عند انقطاع الإنترنت.

1. إنشاء صفحة offline

أنشئ صفحة جديدة في pages/_offline.js:

export default function OfflinePage() {
  return (
    <div style={{
      minHeight: '100vh',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      flexDirection: 'column',
      fontFamily: 'system-ui, sans-serif',
      padding: '1.5rem',
      textAlign: 'center'
    }}>
      <h1>أنت حالياً بدون اتصال بالإنترنت</h1>
      <p>
        بعض المزايا غير متاحة الآن، لكن لا يزال بإمكانك تصفح الصفحات التي تم فتحها مسبقاً.
      </p>
      <p style={{ marginTop: '1rem', fontSize: '0.9rem', color: '#555' }}>
        أعد المحاولة عند توفر اتصال بالشبكة.
      </p>
    </div>
  )
}

2. إعداد Service Worker لإرجاع صفحة Offline

يمكننا استخدام workbox داخل next-pwa لاستبدال الرد في حالة عدم وجود اتصال. في الإصدارات الحديثة، تحتاج إلى custom worker، لكن لتبسيط الفكرة سنضيف نمطاً في runtimeCaching يعيد صفحة offline عند فشل الطلب.

عدّل next-pwa.config.js لإضافة نمط لصفحة _offline إن لزم، أو اعتمد على آلية NetworkFirst مع fallback من خلال كود مخصص في Service Worker (خارج نطاق هذا الدليل التفصيلي). الفكرة الأساسية:

  • حاول جلب الصفحة من الشبكة.
  • إذا فشلت (أوفلاين) ولم توجد في الكاش، أرجع /_offline.

في التطبيقات الإنتاجية الكبيرة يمكن أن تبني Service Worker مخصصاً تستخدم فيه self.addEventListener('fetch', ...) وevent.respondWith للتحكم الكامل في سلوك الأوفلاين.

التحديثات: كيف تتعامل مع الإصدارات الجديدة؟

عند نشر إصدار جديد من تطبيقك، تحتاج لتحديث Service Worker والكاش. في إعدادنا:

  • skipWaiting: true يجعل Service Worker الجديد يصبح فعالاً فوراً بعد التثبيت.
  • المستخدم قد يرى بعض الموارد من الكاش القديم حتى يتم التحديث بالكامل، خاصة مع استراتيجية Stale While Revalidate.

أفضل ممارسة هي:

  • استخدام NetworkFirst للمحتوى الحساس الذي يجب أن يكون محدثاً قدر الإمكان.
  • إظهار رسالة لطيفة للمستخدم عند تحديث التطبيق (يمكن عملها عبر التواصل بين Service Worker والواجهة باستخدام postMessage).

تحسين تجربة المستخدم على الموبايل

لكي يشعر المستخدم أن تطبيقك PWA Next.js offline هو تطبيق جوال حقيقي، انتبه للنقاط التالية:

  1. تصميم Responsive يدعم الشاشات الصغيرة.
  2. إخفاء Navigation Bar بتحديد display: "standalone" في manifest.
  3. استخدام أيقونات عالية الدقة (192 و512 بكسل على الأقل).
  4. ضبط theme-color ليتماشى مع ألوان العلامة التجارية.
  5. تجربة التثبيت على أجهزة أندرويد وiOS واختبار العمل أوفلاين فعلياً.

اختبار PWA Next.js offline عملياً

بعد تنفيذ الخطوات السابقة، قم بالتالي:

  1. شغّل التطبيق في وضع الإنتاج:
    npm run build
    npm run start
    
  2. افتحه في Chrome ثم افتح DevTools > Application > Manifest للتأكد من أن:
    • manifest.json مُعلّق بشكل صحيح.
    • الأيقونات معروضة.
    • PWA installable (قابل للتثبيت).
  3. من تبويب Application > Service Workers تأكد من حالة Service Worker.
  4. من تبويب Network اختر Offline من قائمة Throttling.
  5. قم بإعادة تحميل الصفحة ولاحظ أن:
    • الصفحات التي تمت زيارتها سابقاً تُحمّل من الكاش.
    • في حال طلب صفحة جديدة غير محفوظة، يمكن إظهار صفحة أوفلاين المخصصة.

نصائح أمنية عند بناء PWA

بما أن PWA يعتمد بقوة على التخزين في المتصفح، يجب أن تراعي بعض ممارسات الأمان:

أين تذهب بعد ذلك؟

بعد الانتهاء من إعداد PWA Next.js offline، يمكنك توسيع التطبيق بـ:

خلاصة

بناء PWA Next.js offline لا يعني فقط تفعيل مكتبة next-pwa؛ بل يتطلب فهم كيفية عمل Service Workers، واستراتيجيات الكاش، وتجربة المستخدم في وضع الأوفلاين.

باختصار، الخطوات الأساسية هي:

  1. إعداد مشروع Next.js وتثبيت next-pwa.
  2. إضافة manifest.json وربطه في _document.js.
  3. تفعيل Service Worker عبر next.config.js.
  4. تخصيص runtimeCaching لاستراتيجيات التخزين.
  5. إنشاء صفحة أوفلاين وتحسين تجربة المستخدم على الموبايل.

باتباع هذا الدليل، يمكنك تحويل أي مشروع Next.js إلى تطبيق PWA كامل يدعم العمل أوفلاين، ويحافظ على أداء عالٍ وتجربة مستخدم مميزة على مختلف الأجهزة.

حول المحتوى:

دليل عملي لبناء Progressive Web App باستخدام Next.js وNext-PWA: الإعداد، تخزين الموارد أوفلاين، استراتيجيات التحديث، وتحسين تجربة المستخدم على الموبايل.

هل كان هذا مفيدًا لك؟

أضف تعليقك