PWA (Progressive Web App) — یک برنامه وب است که از قابلیتهای مدرن مرورگر برای کار کردن مانند یک برنامه بومی استفاده میکند: سریع بارگذاری میشود، آفلاین کار میکند، اعلانهای فشاری ارسال میکند و روی صفحه اصلی نصب میشود. در پایه PWA سه فناوری قرار دارند: Service Worker، مانیفست و HTTPS. Service Worker — اسکریپتی است که مرورگر آن را در پسزمینه و جدا از صفحه وب اجرا میکند و قابلیتهایی را باز میکند که برای سایتهای عادی غیرقابل دسترسی است: رهگیری درخواستهای شبکه، کش کردن منابع، همگامسازی پسزمینه و اعلانهای فشاری. مانیفست — فایل JSON است که به مرورگر میگوید برنامه هنگام نصب روی دستگاه چگونه باید به نظر برسد: نام، آیکونها، رنگ تم، جهت صفحه. بدون HTTPS، Service Worker کار نمیکند — این یک الزام امنیتی اجباری است. PWA با هر مرورگر مدرنی سازگار است و نیازی به انتشار در فروشگاه برنامه ندارد. کاربر سایت را باز میکند، پیشنهاد نصب برنامه را میبیند، دکمه «افزودن به صفحه اصلی» را کلیک میکند — و برنامه آماده است. برای کسبوکار، PWA به معنای پوشش هر مخاطبی بدون هزینه توسعه جداگانه برای iOS و Android، سرعت بارگذاری بالا حتی در شبکههای کند و جذب از طریق اعلانهای فشاری است. در مقاله بررسی خواهیم کرد که Service Worker چگونه کار میکند، چگونه مانیفست را جمعآوری کنیم، از چه استراتژیهای کش استفاده کنیم و چگونه دسترسی آفلاین را فراهم کنیم.
نکات مهم
نکات مهم
Progressive Web App (PWA) — رویکردی برای توسعه برنامههای وب است که بهترین کیفیتهای وب و برنامههای بومی را ترکیب میکند. این اصطلاح توسط فرانچسکو بریمن (Francesco Berriman) در سال ۲۰۱۵ معرفی شد و Google فعالانه PWA را به عنوان جایگزینی برای برنامههای ساده موبایل ترویج میکند. ایده اصلی: وبسایت به تدریج بسته به قابلیتهای مرورگر و دستگاه بهبود مییابد. اگر مرورگر از Service Worker پشتیبانی کند — حالت آفلاین متصل میشود. اگر از مانیفست پشتیبانی کند — دکمه «نصب» ظاهر میشود. اگر API اعلانها وجود داشته باشد — برنامه میتواند push ارسال کند. کاربر روی دستگاه ضعیف با اینترنت کند نسخه پایه سایت را دریافت میکند، و روی گوشی هوشمند مدرن — یک برنامه کامل با آیکون روی دسکتاپ.
PWA نیازی به نصب از طریق فروشگاه برنامه ندارد. یک لینک کافی است. این مشکل اصلی برنامههای موبایل — مانع ورود بالا — را حل میکند. کاربر به Google Play یا App Store نمیرود، منتظر دانلود ۱۰۰ مگابایت نمیماند، دهها مجوز نمیدهد. او فقط سایت را باز میکند و مرورگر نصب برنامه را پیشنهاد میکند. اگر کاربر امتناع کند — باز هم از سایت استفاده میکند. و اگر موافقت کند — آیکون روی صفحه اصلی ظاهر میشود و برنامه مانند بومی باز میشود: بدون نوار آدرس مرورگر، با حالت تمام صفحه و راهاندازی سریع.
از نظر فنی، PWA باید سه معیار را برآورده کند: از طریق HTTPS (اتصال امن) کار کند، Service Worker (اسکریپت پردازش پسزمینه) داشته باشد و مانیفست (Web App Manifest) را شامل شود. این سه مؤلفه یک سایت معمولی را به یک برنامه قابل نصب تبدیل میکنند.
Service Worker — اسکریپت JavaScript است که مرورگر آن را در یک رشته جداگانه، مستقل از صفحه وب اجرا میکند. او به DOM دسترسی ندارد، نمیتواند مستقیماً با رابط تعامل کند، اما میتواند درخواستهای شبکه را رهگیری و تغییر دهد، کش را مدیریت کند، اعلانهای فشاری را پردازش کند و همگامسازی پسزمینه را انجام دهد. Service Worker مانند یک پروکسی سرور بین مرورگر و شبکه کار میکند: هر درخواست از صفحه از Service Worker عبور میکند که تصمیم میگیرد — داده را از کش برگرداند، از سرور درخواست کند یا هر دو را انجام دهد.
Service Worker بر اساس چرخه حیات خودش زندگی میکند، نه وابسته به صفحه باز. او نصب میشود، فعال میشود و حتی پس از بسته شدن تمام برگههای سایت در پسزمینه کار میکند. این به PWA اجازه میدهد اعلانهای فشاری دریافت کند و کش را در پسزمینه، بدون دخالت کاربر، بهروز کند.
Service Worker چهار مرحله را طی میکند: ثبت، نصب، فعالسازی و بیکاری/پایان.
ثبت. مرورگر لینکی به فایل JS Service Worker دریافت میکند و دانلود را آغاز میکند. ثبت از JavaScript معمولی در صفحه انجام میشود:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW ثبت شد:', registration.scope);
})
.catch(error => {
console.log('ثبت SW ناموفق بود:', error);
});
}نصب. پس از دانلود موفق، مرورگر رویداد install را راهاندازی میکند. در این مرحله معمولاً منابع کلیدی (چارچوب HTML، CSS، تصاویر اصلی) کش میشوند تا برنامه بتواند آفلاین کار کند. اگر نصب موفقیتآمیز باشد، Service Worker به مرحله بعد میرود. اگر اسکریپت خطا بدهد — نصب لغو میشود و Service Worker قدیمی به کار ادامه میدهد.
self.addEventListener('install', event => {
event.waitUntil(
caches.open('pwa-cache-v1').then(cache => {
return cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js',
'/images/logo.png'
]);
})
);
});فعالسازی. وقتی تمام برگههای سایت بسته میشوند، Service Worker قدیمی پایان مییابد و جدید فعال میشود. رویداد activate برای پاکسازی کشهای قدیمی و مهاجرت دادهها استفاده میشود:
self.addEventListener('activate', event => {
const cacheWhitelist = ['pwa-cache-v2'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
});بیکاری. Service Worker فعال شده درخواستها را رهگیری میکند و رویدادها را پردازش میکند. ممکن است توسط مرورگر برای صرفهجویی در منابع متوقف و در درخواست بعدی دوباره راهاندازی شود. Service Worker رویدادمحور است: فقط تا زمانی که رویدادها را پردازش میکند زنده است.
Service Worker چندین استراتژی کش را پشتیبانی میکند. انتخاب بستگی به نوع منبع و الزامات بهروزرسانی دادهها دارد.
Cache First (ابتدا کش). ابتدا کش بررسی میشود. اگر منبع پیدا شود — از کش برگردانده میشود. اگر نه — درخواست به سرور میرود، پاسخ در کش ذخیره میشود. استراتژی برای منابع ایستا مناسب است: تصاویر، فونتها، CSS، JS. حداکثر سرعت و کار کامل آفلاین را تضمین میکند.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(fetchResponse => {
return caches.open('pwa-cache-v1').then(cache => {
cache.put(event.request, fetchResponse.clone());
return fetchResponse;
});
});
})
);
});Network First (ابتدا شبکه). درخواست ابتدا به سرور میرود. اگر سرور پاسخ دهد — داده به کاربر برگردانده شده و در کش ذخیره میشود. اگر سرور در دسترس نباشد — نسخه کش شده برگردانده میشود. استراتژی برای درخواستهای API، اخبار، محتوایی که باید بهروز باشد اما میتواند آفلاین هم کار کند مناسب است.
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request).then(response => {
return caches.open('pwa-dynamic-v1').then(cache => {
cache.put(event.request, response.clone());
return response;
});
}).catch(() => {
return caches.match(event.request);
})
);
});Stale While Revalidate (قدیمی با بهروزرسانی). پاسخ بلافاصله از کش برگردانده میشود و در پسزمینه درخواستی به سرور برای بهروزرسانی کش ارسال میشود. کاربر محتوا را فوراً میبیند و درخواست بعدی دادههای تازه را دریافت میکند. ایدهآل برای محتوایی که تغییر میکند اما اگر کاربر نسخه چند دقیقه قدیمیتر را ببیند بحرانی نیست.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached => {
const fetchPromise = fetch(event.request).then(response => {
return caches.open('pwa-dynamic-v1').then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
return cached || fetchPromise;
})
);
});مانیفست — فایل JSON است، معمولاً manifest.json، که از طریق تگ <link> در head صفحه HTML متصل میشود. او به مرورگر میگوید برنامه هنگام نصب روی دستگاه چگونه نمایش داده شود: نام، آیکونهای اندازههای مختلف، رنگ پسزمینه، رنگ تم، جهت و حالت نمایش (مرورگر، حداقل UI، تمام صفحه).
{
"name": "PWA Demo App",
"short_name": "PWA Demo",
"description": "برنامه نمایشی PWA",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#3f51b5",
"orientation": "portrait",
"icons": [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}پارامتر display تعیین میکند که برنامه پس از نصب چگونه به نظر برسد. standalone نوار آدرس مرورگر و پنل ناوبری را پنهان میکند — برنامه شبیه بومی به نظر میرسد. fullscreen بدون هیچ عنصر مرورگر از تمام صفحه استفاده میکند. minimal-ui حداقل عناصر مرورگر (دکمههای بازگشت و بهروزرسانی) را باقی میگذارد.
آیکونها باید حداقل در دو اندازه آماده شوند: ۱۹۲x۱۹۲ و ۵۱۲x۵۱۲ پیکسل. فرمت PNG با پشتیبانی از پارامتر purpose (مثلاً maskable) به مرورگر اجازه میدهد آیکون را با شکل بدنه دستگاه تطبیق دهد — در Android آیکون ممکن است به مربع گرد شده بریده شود. پس از اتصال مانیفست، مرورگر Chrome در Android با رعایت شرایط شروع به نمایش بنر «افزودن به صفحه اصلی» میکند: HTTPS، Service Worker ثبتشده، مانیفست صحیح و حداقل دو بازدید با فاصله ۵ دقیقه.
PWA میتواند مانند یک برنامه بومی اعلانهای فشاری ارسال کند. برای این کار از دو API استفاده میشود: Push API (ارسال سروری) و Notification API (نمایش روی دستگاه). Service Worker رویداد push را حتی اگر برنامه باز نباشد دریافت میکند و میتواند اعلانی با عنوان، متن و آیکون نشان دهد.
برای دریافت اعلانهای فشاری کاربر باید اجازه دهد:
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
console.log('Push مجاز است');
}
});Service Worker در رویداد push مشترک میشود و اعلان را نمایش میدهد:
self.addEventListener('push', event => {
const data = event.data.json();
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/icon-192x192.png',
badge: '/icons/badge-72x72.png',
actions: [
{ action: 'open', title: 'باز کردن' },
{ action: 'close', title: 'بستن' }
]
});
});
self.addEventListener('notificationclick', event => {
event.notification.close();
if (event.action === 'open') {
clients.openWindow('/');
}
});برای ارسال push از سرور از پروتکل Web Push (VAPID) استفاده میشود. سرور پیام را رمزگذاری کرده و از طریق سرویس push مرورگر (Firebase Cloud Messaging برای Chrome، Mozilla Autopush برای Firefox) ارسال میکند. اشتراک کاربر (شیء PushSubscription) باید در زمان ثبت در سرور ذخیره شود.
PWA باید سریع باشد. Google Lighthouse — ابزار حسابرسی که PWA را بر اساس چکلیست بررسی میکند: ثبت Service Worker، پاسخ ۲۰۰ در دسترسی آفلاین، مانیفست صحیح، HTTPS، اندازه صحیح آیکونها، بارگذاری سریع در شبکههای کند. حداقل نمره قبولی برای PWA — ۸۰ از ۱۰۰ در مقیاس Lighthouse. برنامههایی با نمره زیر ۸۰ بنر نصب در Chrome دریافت نمیکنند.
معیارهای کلیدی عملکرد برای PWA — First Contentful Paint (FCP) تا ۱.۸ ثانیه، Largest Contentful Paint (LCP) تا ۲.۵ ثانیه، Time to Interactive (TTI) تا ۳.۵ ثانیه. Service Worker میتواند با کش کردن HTML و CSS بحرانی در زمان نصب، FCP و LCP را به طور قابل توجهی بهبود بخشد. استراتژی Cache First برای استاتیک و Stale While Revalidate برای API بهترین تجربه کاربری را ارائه میدهد.
یکی از قابلیتهای اصلی PWA — کار بدون اینترنت است. Service Worker درخواستها را رهگیری کرده و نسخههای کش شده صفحات را برمیگرداند. اگر کاربر سعی کند صفحهای را باز کند که در کش نیست، میتوان یک صفحه جایگزین سفارشی نشان داد:
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
}).catch(() => {
return caches.match('/offline.html');
})
);
});همگامسازی پسزمینه (Background Sync) امکان به تأخیر انداختن ارسال داده به سرور را در صورت آفلاین بودن دستگاه فراهم میکند. Service Worker درخواست را ذخیره کرده و وقتی اتصال برقرار شد به طور خودکار ارسال میکند:
self.addEventListener('sync', event => {
if (event.tag === 'sync-messages') {
event.waitUntil(sendMessages());
}
});
function sendMessages() {
return caches.open('pwa-pending-v1').then(cache => {
return cache.keys().then(requests => {
return Promise.all(requests.map(request => {
return fetch(request).then(() => cache.delete(request));
}));
});
});
}Chrome DevTools پنل Application را ارائه میدهد که در آن میتوان Service Worker (ثبت، وضعیت، کش، push) را اشکالزدایی کرد، مانیفست را بررسی کرد، کش را پاک کرد و اعلانهای فشاری خود را برای آزمایش ایجاد کرد. برگه Network با شبیهسازی حالت آفلاین به بررسی عملکرد کش کمک میکند. Lighthouse در پنل Audits یک حسابرسی کامل PWA با توصیهها ارائه میدهد.
Workbox — کتابخانهای از Google که ایجاد Service Worker را ساده میکند. به جای نوشتن دستی استراتژیهای کش، Workbox ماژولهای آماده ارائه میدهد:
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
/\.(?:png|jpg|jpeg|svg|gif)$/,
new StaleWhileRevalidate()
);Workbox با باندلرها (Webpack, Vite) یکپارچه میشود و به طور خودکار مانیفست پیشکش را تولید میکند. PWA Builder (pwabuilder.com) از Microsoft همه فایلهای PWA را آنلاین تولید میکند: Service Worker، مانیفست، آیکونها، قالب HTML.
FAQ
PWA — سایتی است که پس از نصب روی گوشی مانند یک برنامه معمولی کار میکند: آیکون روی دسکتاپ، دسترسی آفلاین، اعلانهای فشاری، حالت تمام صفحه بدون نوار آدرس مرورگر. در عین حال نیازی به مراجعه به App Store یا Google Play نیست — نصب با یک کلیک از مرورگر انجام میشود.
برنامه بومی برای یک پلتفرم خاص (Swift برای iOS، Kotlin برای Android) نوشته میشود، نیاز به انتشار در فروشگاه و نصب دستی دارد. PWA — وبسایتی است که با HTML، CSS و JavaScript نوشته شده و میتواند از طریق مرورگر روی دستگاه نصب شود. PWA فضای زیادی اشغال نمیکند (فقط کش)، به طور خودکار بهروز میشود و توسط تمام مرورگرهای مدرن پشتیبانی میشود.
Chrome، Firefox، Safari (از iOS 11.3)، Edge، Samsung Internet، Opera. Service Worker توسط همه مرورگرهای مدرن به جز Internet Explorer پشتیبانی میشود. Safari پشتیبانی محدودی از اعلانهای فشاری دارد، اما قابلیتهای پایه PWA (نصب روی صفحه اصلی، دسترسی آفلاین) کار میکنند.
بله. برای این کار باید مانیفست (manifest.json) اضافه کرد، Service Worker (sw.js) ایجاد و ثبت کرد، سایت را به HTTPS منتقل کرد، متا تگها و آیکونها اضافه کرد. خود سایت نیازی به بازنویسی ندارد اگر روی JavaScript کار میکند و HTML برمیگرداند. اگر سایت کاملاً سمت سرور باشد (MPA)، میتوان Service Worker را به عنوان لایه کش بدون تغییر معماری اضافه کرد.
وقتی کاربر PWA را باز میکند، مرورگر بررسی میکند که آیا فایل Service Worker روی سرور تغییر کرده است. اگر فایل حداقل یک بایت تفاوت داشته باشد، مرورگر Service Worker جدید را دانلود کرده و نصب آن را شروع میکند. Service Worker قدیمی تا بسته شدن تمام برگههای برنامه به کار ادامه میدهد. پس از بسته شدن برگهها، Service Worker جدید فعال شده و جایگزین قدیمی میشود. کاربر میتواند با بارگذاری مجدد صفحه، برنامه را بهروزرسانی اجباری کند.
PWA موجه است اگر هدف پوشش حداکثر مخاطب بدون هزینه توسعه برای دو پلتفرم باشد، اگر برنامه نیاز به دسترسی عمیق به سختافزار (Bluetooth، NFC، دوربین در پسزمینه) نداشته باشد، اگر محتوا frequently تغییر کند. برای برنامههای پیچیده (بازیها، ویرایشگرهای ویدیو) برنامه بومی ترجیح داده میشود. PWA اغلب به عنوان کانال اضافی یا به عنوان MVP قبل از برنامه کامل استفاده میشود.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید