Service Worker چیست و چگونه یک سایت معمولی را به PWA تبدیل می‌کند؟

Service Worker چیست و چگونه یک سایت معمولی را به PWA تبدیل می‌کند؟

توسعه‌دهنده فرانت‌اند

امکان کارکردن در شرایط آفلاین، Cache کردن منابع، کنترل درخواست‌های شبکه، ارسال Push Notification و نصب سایت روی دستگاه، بخشی از قابلیت‌هایی هستند که می‌توانند یک وب‌سایت معمولی را به یک Progressive Web App یا PWA تبدیل کنند.

Service Worker چیست و چگونه یک سایت معمولی را به PWA تبدیل می‌کند؟

صارم توکلی

۱۲ دقیقه مطالعه

۰ نفر

۱۴۰۵/۷/۴

Service Worker چیست و چگونه یک سایت معمولی را به PWA تبدیل می‌کند؟

وب‌سایت‌های مدرن دیگر فقط مجموعه‌ای از صفحات HTML نیستند. با استفاده از تکنولوژی‌هایی مانند Service Worker، می‌توان قابلیت‌هایی را به وب‌سایت اضافه کرد که تا سال‌ها بیشتر در دنیای اپلیکیشن‌های Native دیده می‌شدند.

امکان کارکردن در شرایط آفلاین، Cache کردن منابع، کنترل درخواست‌های شبکه، ارسال Push Notification و نصب سایت روی دستگاه، بخشی از قابلیت‌هایی هستند که می‌توانند یک وب‌سایت معمولی را به یک Progressive Web App یا PWA تبدیل کنند.

اما Service Worker دقیقاً چیست؟

کجا اجرا می‌شود؟

چه تفاوتی با JavaScript معمولی دارد؟

و مهم‌تر از همه، چگونه می‌توان با آن یک سایت معمولی را به PWA تبدیل کرد؟

در این مقاله قدم‌به‌قدم این مفاهیم را بررسی می‌کنیم.


Service Worker چیست؟

Service Worker یک اسکریپت JavaScript است که مرورگر آن را در یک محیط جدا از صفحه وب اجرا می‌کند.

برخلاف JavaScript معمولی که مستقیماً با صفحه و DOM کار می‌کند، Service Worker بیشتر نقش یک لایه واسط بین Application و Network را دارد.

می‌توان معماری آن را به شکل زیر تصور کرد:

User
  ↓
Browser
  ↓
Service Worker
  ↓
Network / Cache
  ↓
Server

Service Worker می‌تواند درخواست‌های Network را مشاهده و در صورت نیاز آن‌ها را از Cache پاسخ دهد.

به همین دلیل یکی از پایه‌های اصلی معماری PWA محسوب می‌شود.


Service Worker کجا اجرا می‌شود؟

یکی از نکات مهم این است که Service Worker داخل صفحه اصلی اجرا نمی‌شود.

در واقع:

Main Thread
    │
    ├── UI
    ├── DOM
    └── Application JavaScript

Service Worker
    │
    ├── Network
    ├── Cache
    └── Background Tasks

Service Worker در یک Context جداگانه اجرا می‌شود.

به همین دلیل نمی‌تواند مستقیماً به DOM دسترسی داشته باشد.

مثلاً این کار در Service Worker امکان‌پذیر نیست:

document.querySelector('#app');

اما می‌تواند با APIهای مخصوص خودش با Cache و Requestهای شبکه کار کند.


چرا Service Worker مهم است؟

Service Worker چند قابلیت مهم را در اختیار Web Application قرار می‌دهد:

  • Cache کردن منابع

  • پشتیبانی از Offline

  • کنترل Requestهای شبکه

  • پاسخ دادن از Cache

  • Background Processing در برخی سناریوها

  • Push Notification

  • کمک به ساخت PWA

در نتیجه می‌توان تجربه‌ای ساخت که حتی در شرایطی که اینترنت ضعیف است یا موقتاً وجود ندارد، بخش‌هایی از Application همچنان قابل استفاده باشند.


Service Worker چه تفاوتی با JavaScript معمولی دارد؟

JavaScript معمولی معمولاً به Lifecycle همان صفحه وابسته است.

مثلاً:

Open Page
   ↓
JavaScript Runs
   ↓
Close Page
   ↓
JavaScript Stops

اما Service Worker مستقل‌تر از یک Page است.

مثلاً:

Browser
   ↓
Register Service Worker
   ↓
Install
   ↓
Activate
   ↓
Handle Requests

حتی ممکن است Service Worker زمانی که صفحه خاصی باز نیست نیز برای برخی رویدادهای پشتیبانی‌شده فعال شود.

البته Service Worker یک Process دائمی نیست و مرورگر می‌تواند آن را متوقف و در صورت نیاز دوباره راه‌اندازی کند.


Service Worker چگونه ثبت می‌شود؟

ابتدا باید Service Worker را در Application ثبت کنیم.

مثلاً در JavaScript اصلی:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js');
}

اینجا مرورگر بررسی می‌کند که آیا Service Worker را پشتیبانی می‌کند یا خیر.

سپس فایل:

/sw.js

به عنوان Service Worker ثبت می‌شود.


Service Worker Lifecycle

Service Worker یک Lifecycle مشخص دارد.

مراحل اصلی آن عبارت‌اند از:

Register
   ↓
Install
   ↓
Waiting
   ↓
Activate
   ↓
Control

درک این Lifecycle برای Debug کردن PWA بسیار مهم است.


مرحله اول: Register

در مرحله اول، Application از مرورگر می‌خواهد Service Worker را ثبت کند:

navigator.serviceWorker.register('/sw.js');

اگر ثبت موفق باشد، مرورگر Service Worker را برای Scope مشخص‌شده مدیریت می‌کند.


مرحله دوم: Install

پس از Register، Service Worker وارد مرحله Install می‌شود.

در این مرحله معمولاً منابع اولیه Application را Cache می‌کنیم.

مثلاً:

const CACHE_NAME = 'app-v1';

const ASSETS = [
  '/',
  '/index.html',
  '/styles.css',
  '/app.js'
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(ASSETS))
  );
});

در این مثال، هنگام Install فایل‌های مشخص‌شده وارد Cache می‌شوند.


مرحله سوم: Activate

پس از Install، Service Worker می‌تواند وارد مرحله Activate شود.

این مرحله معمولاً برای پاک کردن Cacheهای قدیمی کاربرد دارد.

مثلاً:

self.addEventListener('activate', event => {
  const validCaches = ['app-v2'];

  event.waitUntil(
    caches.keys().then(keys =>
      Promise.all(
        keys
          .filter(key => !validCaches.includes(key))
          .map(key => caches.delete(key))
      )
    )
  );
});

در اینجا می‌توان Cacheهای قدیمی را حذف کرد.


مرحله چهارم: کنترل Requestها

یکی از قدرتمندترین قابلیت‌های Service Worker، دریافت Event مربوط به Requestهای شبکه است.

مثلاً:

self.addEventListener('fetch', event => {
  console.log(event.request.url);
});

هر زمان صفحه تحت کنترل Service Worker یک Request ایجاد کند، این Event می‌تواند اجرا شود.

اینجاست که می‌توانیم تصمیم بگیریم:

Request
   ↓
Cache؟
 ┌─┴─┐
Yes  No
 ↓    ↓
Cache Network

ساده‌ترین استراتژی: Cache First

یکی از معروف‌ترین استراتژی‌های Caching، Cache First است.

منطق آن:

Request
   ↓
Cache
   ↓
Found?
 ┌─┴─┐
Yes  No
 ↓    ↓
Return Network
       ↓
      Cache

یک نمونه ساده:

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(cachedResponse => {
        return cachedResponse || fetch(event.request);
      })
  );
});

اگر Response در Cache باشد، همان نسخه برگردانده می‌شود.

در غیر این صورت، Request به Network ارسال می‌شود.


Network First چیست؟

در برخی سناریوها بهتر است ابتدا Network را امتحان کنیم.

مثلاً برای داده‌هایی که مرتب تغییر می‌کنند:

Request
   ↓
Network
   ↓
Success?
 ┌─┴─┐
Yes  No
 ↓    ↓
Save  Cache
      ↓
    Response

نمونه ساده:

self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request)
      .catch(() => caches.match(event.request))
  );
});

در این حالت ابتدا نسخه جدید از Server دریافت می‌شود.

اگر Network در دسترس نباشد، Cache می‌تواند به عنوان Fallback عمل کند.


چرا یک Strategy برای همه چیز مناسب نیست؟

یکی از اشتباهات رایج این است که برای تمام Requestها یک Strategy یکسان تعریف کنیم.

اما نوع داده اهمیت زیادی دارد.

مثلاً:

نوع محتواStrategy مناسبفونتCache FirstCSSCache FirstJavaScript VersionedCache FirstتصاویرCache FirstAPIهای پویاNetwork Firstداده‌های حساسسیاست دقیق‌ترصفحات HTMLبسته به معماری

بنابراین Service Worker باید بر اساس نوع Request طراحی شود.


Offline Mode چگونه کار می‌کند؟

یکی از جذاب‌ترین قابلیت‌های PWA، امکان استفاده از بخش‌هایی از Application بدون اینترنت است.

فرض کنید کاربر قبلاً سایت را باز کرده است.

Service Worker فایل‌های اصلی را Cache کرده:

index.html
app.js
styles.css
logo.svg

حالا اینترنت قطع می‌شود.

کاربر دوباره سایت را باز می‌کند:

Browser
   ↓
Service Worker
   ↓
Cache
   ↓
Cached Application

در این حالت می‌توانیم Application Shell را از Cache نمایش دهیم.


Application Shell چیست؟

Application Shell به بخش‌های اصلی رابط کاربری گفته می‌شود که برای نمایش اولیه Application لازم هستند.

مثلاً:

Header
Navigation
Layout
CSS
JavaScript
Icons

این بخش‌ها را می‌توان Cache کرد تا Application حتی بدون Network نیز بتواند ساختار اصلی خود را نمایش دهد.


آیا PWA یعنی سایت کاملاً Offline است؟

خیر.

این یک تصور اشتباه رایج است.

PWA لزوماً به این معنی نیست که تمام قابلیت‌های سایت بدون اینترنت کار می‌کنند.

برای مثال یک فروشگاه آنلاین ممکن است بتواند:

Home Page       ✓
Product Cache   ✓
UI              ✓

را Offline نمایش دهد.

اما:

پرداخت
ثبت سفارش
اطلاعات لحظه‌ای

به Network نیاز داشته باشند.

بنابراین باید مشخص کنیم کدام بخش Application واقعاً قابلیت Offline دارد.


Service Worker و PWA چه رابطه‌ای دارند؟

PWA یک تکنولوژی واحد نیست.

در واقع PWA مجموعه‌ای از قابلیت‌ها و استانداردهای Web است که تجربه‌ای شبیه Application ایجاد می‌کند.

Service Worker یکی از اجزای مهم این معماری است.

در کنار آن معمولاً مواردی مانند:

Web App Manifest
HTTPS
Responsive Design
Offline Strategy
Installability

نیز اهمیت دارند.


Web App Manifest چیست؟

برای اینکه یک Web App بتواند تجربه نصب‌شدن روی دستگاه را ارائه دهد، معمولاً از فایل Manifest استفاده می‌شود.

مثلاً:

{
  "name": "My Application",
  "short_name": "My App",
  "start_url": "/",
  "display": "standalone",
  "icons": [
    {
      "src": "/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ]
}

این فایل اطلاعاتی درباره Application در اختیار مرورگر قرار می‌دهد.

مثلاً:

  • نام Application

  • آیکون

  • صفحه شروع

  • نحوه نمایش

  • Theme

  • رنگ پس‌زمینه


HTTPS چرا مهم است؟

Service Worker به دلایل امنیتی باید در محیط امن اجرا شود.

در Production معمولاً باید سایت از:

HTTPS

استفاده کند.

یک استثنای مهم برای توسعه:

localhost

است که مرورگرها معمولاً آن را به عنوان محیط امن توسعه در نظر می‌گیرند.


Scope در Service Worker چیست؟

Service Worker فقط می‌تواند صفحات داخل Scope خودش را کنترل کند.

اگر فایل اینجا باشد:

/scripts/sw.js

به صورت پیش‌فرض Scope آن محدودتر از حالتی است که Service Worker در Root قرار داشته باشد.

برای مثال:

/sw.js

معمولاً می‌تواند Scope گسترده‌تری داشته باشد.

این موضوع هنگام طراحی ساختار پروژه اهمیت دارد.


Cache API چیست؟

Service Worker معمولاً برای مدیریت Cache از Cache API استفاده می‌کند.

مثلاً:

const cache = await caches.open('app-v1');

await cache.put('/data.json', response);

و برای دریافت:

const cached = await caches.match('/data.json');

Cache API با HTTP Cache مرورگر یکی نیست.

این دو سیستم می‌توانند در کنار یکدیگر وجود داشته باشند.


Service Worker و HTTP Cache

این دو مفهوم گاهی با یکدیگر اشتباه گرفته می‌شوند.

HTTP Cache

توسط Browser و بر اساس Headerهایی مانند:

Cache-Control
ETag
Expires

مدیریت می‌شود.

Service Worker Cache

توسط Application و Service Worker با استفاده از Cache API کنترل می‌شود.

یعنی:

HTTP Cache
    +
Service Worker Cache

می‌توانند هر دو در معماری یک سایت وجود داشته باشند.


Push Notification

Service Worker می‌تواند در معماری Push Notification نیز نقش داشته باشد.

در یک سناریوی کلی:

Server
   ↓
Push Service
   ↓
Browser
   ↓
Service Worker
   ↓
Notification

Service Worker می‌تواند Event مربوط به Push را دریافت کرده و Notification را نمایش دهد.

البته این قابلیت نیازمند Permission کاربر و پیاده‌سازی سمت Server نیز هست.


Background Sync چیست؟

در برخی سناریوها Service Worker می‌تواند برای مدیریت عملیات‌هایی که باید بعداً انجام شوند نیز مورد استفاده قرار گیرد.

مثلاً تصور کنید کاربر در شرایط Offline فرمی را ثبت می‌کند.

Application می‌تواند اطلاعات را موقتاً نگه دارد و پس از بازگشت Network، عملیات را تکمیل کند.

ایده کلی:

User Action
    ↓
Offline
    ↓
Store Request
    ↓
Network Returns
    ↓
Sync
    ↓
Server

پشتیبانی دقیق این قابلیت‌ها به مرورگر و API مورد استفاده بستگی دارد، بنابراین باید هنگام پیاده‌سازی Compatibility را بررسی کرد.


Service Worker چه محدودیت‌هایی دارد؟

Service Worker بسیار قدرتمند است، اما نباید تصور کنیم جایگزین Backend یا یک Application Native است.

از جمله محدودیت‌ها:

  • دسترسی مستقیم به DOM ندارد

  • Lifecycle آن توسط Browser مدیریت می‌شود

  • همیشه در حال اجرا نیست

  • باید سیاست Cache دقیقی داشته باشد

  • مدیریت Versionها اهمیت زیادی دارد

  • Debug کردن Cacheهای قدیمی می‌تواند دشوار باشد

بنابراین طراحی Service Worker باید بخشی از معماری Application باشد.


مشکل معروف Cacheهای قدیمی

فرض کنید نسخه اول Application را منتشر کرده‌ایم:

app-v1

بعد نسخه جدید:

app-v2

را منتشر می‌کنیم.

اگر Service Worker همچنان Cache قدیمی را ارائه کند، ممکن است کاربر نسخه قبلی Application را ببیند.

به همین دلیل معمولاً هنگام تغییر نسخه باید:

Install New Worker
        ↓
Activate
        ↓
Delete Old Cache
        ↓
Use New Assets

را به شکل صحیح مدیریت کرد.


آیا ساخت PWA فقط با نوشتن یک Service Worker انجام می‌شود؟

خیر.

برای یک PWA حرفه‌ای باید چند بخش را در نظر گرفت:

Responsive UI
      +
HTTPS
      +
Web App Manifest
      +
Service Worker
      +
Caching Strategy
      +
Offline Strategy
      +
Installability

Service Worker بخش مهمی از PWA است، اما تمام PWA نیست.


چگونه یک سایت معمولی را به PWA تبدیل کنیم؟

اگر یک سایت معمولی داشته باشیم، مسیر کلی می‌تواند این باشد:

مرحله اول: بررسی HTTPS

سایت باید روی HTTPS اجرا شود.

مرحله دوم: ایجاد Manifest

اطلاعات Application را در Manifest تعریف می‌کنیم.

مرحله سوم: ایجاد Service Worker

فایل Service Worker را ایجاد و Register می‌کنیم.

مرحله چهارم: Cache کردن منابع ضروری

منابع اصلی Application را Cache می‌کنیم.

مرحله پنجم: تعریف Fetch Strategy

مشخص می‌کنیم هر نوع Request چگونه مدیریت شود.

مرحله ششم: Offline Fallback

برای شرایط Offline یک تجربه مناسب طراحی می‌کنیم.

مرحله هفتم: مدیریت Versioning

Cacheهای قدیمی را مدیریت و در صورت نیاز حذف می‌کنیم.

مرحله هشتم: تست

Application را در شرایط مختلف بررسی می‌کنیم:

Online
Offline
Slow Network
Cache Hit
Cache Miss
New Version
Old Version

یک ساختار ساده برای PWA

یک پروژه ساده می‌تواند ساختاری شبیه این داشته باشد:

project/
│
├── index.html
├── app.js
├── styles.css
├── manifest.json
├── sw.js
│
└── icons/
    ├── icon-192.png
    └── icon-512.png

و جریان کلی:

Browser
   ↓
index.html
   ↓
app.js
   ↓
Register sw.js
   ↓
Service Worker
   ↓
Cache / Network

Service Worker را با Cache اشتباه نگیریم

Service Worker خودش Cache نیست.

این نکته بسیار مهم است.

Service Worker یک Programmable Network Proxy در سمت Browser است.

یعنی می‌تواند روی نحوه دریافت و پاسخ‌دهی Requestها منطق اعمال کند.

مثلاً:

Request
   ↓
Service Worker
   ↓
 ┌──────────────┐
 │ Cache First  │
 │ Network First│
 │ Stale While  │
 │ Revalidate   │
 └──────────────┘

پس قدرت اصلی Service Worker در این است که منطق مورد نیاز Application را روی فرآیند Request/Response اعمال می‌کند.


Service Worker و Performance

Service Worker می‌تواند Performance را به شکل قابل توجهی بهبود دهد؛ به‌خصوص برای منابعی که قبلاً دریافت شده‌اند.

مثلاً:

First Visit
   ↓
Network
   ↓
Cache

Next Visit
   ↓
Service Worker
   ↓
Cache
   ↓
Fast Response

اما استفاده نادرست از Service Worker می‌تواند نتیجه معکوس داشته باشد.

برای مثال اگر Cache Strategy اشتباه باشد، ممکن است کاربر نسخه قدیمی محتوا را دریافت کند.

بنابراین:

Caching سریع‌تر بودن نیست؛ Caching درست، سریع‌تر بودن است.


آیا Service Worker برای هر سایتی لازم است؟

خیر.

اگر سایت بسیار ساده‌ای دارید که:

  • محتوای کاملاً استاتیک دارد

  • Offline بودن اهمیتی ندارد

  • Notification لازم ندارد

  • Installability هدف پروژه نیست

ممکن است Service Worker ارزش پیچیدگی اضافه را نداشته باشد.

اما برای Applicationهایی مانند:

  • فروشگاه‌های آنلاین

  • داشبوردها

  • ابزارهای تحت وب

  • سیستم‌های مدیریت

  • اپلیکیشن‌های SaaS

  • سرویس‌های محتوایی

  • Web Appهای تعاملی

می‌تواند بسیار ارزشمند باشد.


جمع‌بندی

Service Worker یکی از مهم‌ترین تکنولوژی‌های Web برای ساخت تجربه‌های مدرن و Offline-capable است.

این تکنولوژی به ما اجازه می‌دهد بین Application و Network یک لایه قابل برنامه‌ریزی داشته باشیم.

با استفاده از آن می‌توانیم:

  • منابع را Cache کنیم

  • درخواست‌ها را مدیریت کنیم

  • تجربه Offline بسازیم

  • Cache Strategy تعریف کنیم

  • برخی قابلیت‌های Background را پیاده کنیم

  • Push Notification داشته باشیم

  • و بخشی از مسیر ساخت PWA را فراهم کنیم

اما یک PWA حرفه‌ای فقط با Service Worker ساخته نمی‌شود.

معماری کامل معمولاً ترکیبی از:

Service Worker
       +
Cache API
       +
Web App Manifest
       +
HTTPS
       +
Responsive UI
       +
Offline Strategy

است.

در نهایت Service Worker را می‌توان این‌گونه خلاصه کرد:

Service Worker یک لایه قابل برنامه‌ریزی بین Web Application و Network است که به مرورگر اجازه می‌دهد نحوه Cache و مدیریت برخی درخواست‌ها را کنترل کند.

و همین قابلیت، پایه بسیاری از تجربه‌هایی است که یک وب‌سایت معمولی را به یک Progressive Web App سریع، قابل نصب و تا حدی مستقل از اتصال دائمی به اینترنت تبدیل می‌کنند.