آموزش گام به گام تولید Progressive Web App (PWA)

آموزش گام به گام تولید Progressive Web App (PWA)

امروزه بیشتر مردم از گوشی‌های هوشمند استفاده میکنند و استفاده از کامپیوترهای شخصی در امور روزانه مردم کم‌رنگتر از قبل شده. بنابراین طبیعیه که بیشتر کاربران یک وبسایت، این روزها از طریق گوشی‌های تلفن همراه از وبسایت مورد نظر خود بازدید میکنند. پس خواسته یا ناخواسته، اگر یک وبسایت بخواهد در دنیای تکنولوژی امروز زنده بمونه و کاربران رو به سمت خود جذب کنه، باید روی گوشی‌های تلفن همراه به خوبی به نمایش دربیاد و کاربران رو راضی نگه داره.
البته این موضوع جدیدی نیست و چندین ساله که اکثر وبسایت‌ها با مفاهیم مختلفی مثل compatible بودن با مرورگرهای موبایل و responsive بودن سایت سر و کار دارند و تمام تلاش وبسایت‌ها این هست که وبسایت، به خوبی بر روی مرورگرهای گوشی به نمایش دربیاد. اما امروزه تنها نمایش درست یک وبسایت کافی نیست! موارد دیگری مثل سرعت بارگذاری در مرورگرهای گوشی، انیمیشن‌های مختلف در هنگام اجرا و لود شدن یک وبسایت، فرمان‌پذیری سریع نسبت به حرکات کاربر، شباهت هر چه بیشتر به اپلیکیشن‌های موبایلی و ... هم از دید کاربران بسیار مهمه. به طور مثال طبق برخی آمارها اگر وبسایتی تا 3 ثانیه به طور کامل load نشه حدود 40 درصد کاربران، وبسایت رو ترک خواهند کرد!

بنابراین برای همه ما روشنه که بها دادن به اجرای هرچه بهتر یک وبسایت روی موبایل یکی از ویژگی‌های مورد نیاز هر وبسایت هست. حالا چقدر خوب بود اگر وبسایت ما مانند یک اپلیکیشن native موبایلی برای کاربران اجرا میشد. خب، به همین منظور جامعه‌ی تکنولوژی‌های وب مفهومی رو تحت عنوان اپلیکیشن‌های پیشرونده تحت وب (به انگلیسی Progressive Web Applications یا به طور خلاصه PWA ) رو معرفی کرد.PWA مربوط به یک پلتفرم خاص نیست. خبری از یک فریمورک یا یک کتابخانه جاوااسکریپتی نیست. فقط قابلیتی‌هایی هست که به یک وبسایت ساده اضافه میشه تا وبسایت مورد نظر شبیه به یک اپلیکیشن native به نظر برسه. برای شروع،بیاید این قابلیت‌ها رو بررسی کنیم.

ویژگی‌های یک PWA:

یک PWA به طور کلی سه ویژگی زیر رو داراست:

  1. Reliable: به این معنی که وبسایت به سرعت load شده و در حالت آفلاین نیز قابل اجرا باشه. این مورد میتونه با load کردن از روی cache storage مرورگر اتفاق بیفته که برای هر بار load شدن وبسایت نیازی به اینترنت نبوده و در حالت آفلاین نیز با اجرای یک صفحه cache شده، قابل اجرا باشه.
  2. Fast: به این معنی که به حرکات کاربر مثل کلیک کردن‌ها، لمس کردن گوشی و ... به سرعت پاسخ داده و همچنین سرعت بارگذاری صفحات نیز مانند اپلیکیشن های native بالا باشه.
  3. Engaging: به این معنی که مثل یک اپلیکیشن native عمل کنه. چه از نظر ظاهر و استایل و چه از نظر animationها و navigationها و ... .

PWA ها میتونند بعد از اینکه برای اولین بار کاربر وارد وبسایت شد روی Home Screen گوشی کاربر مانند یک اپلیکیشن native نصب شده و آیکون وبسایت روی صفحه اصلی قرار بگیره. 
کاربر بعد از نصب و کلیک روی Shortcut ساخته شده‌ی اپلیکیشن، وارد وبسایت میشه ولی وبسایت رو مثل یک اپلیکیشن native تجربه خواهد کرد.
همچنین یک PWA میتونه برخی از قابلیت‌های وبسایت رو به صورت آفلاین در اختیار کاربران قرار بده. به این صورت که بعد از نصب PWA اگر کاربران آفلاین بوده و وارد وبسایت بشن، به بعضی از ویژگی‌های وبسایت دسترسی داشته باشند. دقیقا مثل یک اپلیکیشن native که روی گوشی کاربر نصب شده. این ویژگی‌ها توسط service worker ها قابل دسترس خواهند بود که در ادامه توضیح داده خواهند شد.
نکته دیگه اینکه اگر PWA روی گوشی کاربر نصب شده باشه میتونیم از امکان push notification استفاده کرده و برای کاربران notification ارسال کنیم. باز هم درست مثل اپلیکیشن‌های native.
این رو هم باید در نظر گرفت که PWA ها امنیت بالایی دارند. چون تنها در بستر HTTPS امکان استفاده رو خواهند داشت و در غیر این صورت (یعنی اگر HTTPS نباشه) وبسایت ما یک PWA معتبر (یا به اصطلاح valid) نخواهد بود.
حالا چطور این ویژگی‌ها رو در وبسایت خودمون پیاده سازی کنیم؟ برای راحت‌تر شدن کار، گوگل، checklist ای از ویژگی‌هایی که یک PWA باید داشته باشه رو طراحی کرده. برای اینکه به این checklist دسترسی داشته باشید میتونید از لینک زیر استفاده کنید (در ادامه موارد مورد نیاز مطرح میشن):

چک لیست گوگل

همچنین برای اعتبار سنجی یک وبسایت از این نظر که آیا یک PWA معتبر هست یا خیر میتونید در google chrome از افزونه lighthouse استفاده کنید. این افزونه رو از Chrome store میتونید دریافت کنید. بعد از نصب این افزونه، در Developer tools تبی تحت عنوان Audits اضافه میشه که میتونید با کلیک کردن روی اون و انتخاب گزینه Progressive Web App وبسایت مورد نظر رو از نظر معتبر بودن بسنجید. میتونید از لینک زیر برای دریافت این افزونه استفاده کنید:

پلاگین Lighthouse

حالا وقت آن رسیده که بررسی کنیم چه مواردی رو در وبسایت خودمون اضافه کنیم تا وبسایت ما یک PWA معتبر باشه.

می تونی خیلی سریع با کارراهه‌ی "برنامه نویس Front-End شو" وارد دنیای برنامه نویسی وب بشی!

نیازمندی‌ یک PWA:

چطور میتونیم وبسایت ساده خودمون رو به یک PWA تبدیل کنیم؟ برای اینکار بیاید از lighthouse کمک بگیریم و تا آخر این مقاله با یک مثال پیش خواهیم رفت. فرض کنید شما یک وبسایت ساده دارید و قصد دارید که وبسایت رو به PWA تبدیل کنید. ابتدا Lighthouse رو در وبسایت خودتون باز کنید. گزینه Progressive web App رو انتخاب کرده و بر روی Generate report کلیک کنید. با این کار lighthouse شروع به آنالیز کردن وبسایت شما خواهد کرد. این کار ممکنه مدتی طول بکشه. بنابراین صبور باشید.

شکل 1: آنالیز وب سایت توسط Lighthouse
اگر چند لحظه صبر کنید lighthouse لیستی از پیشنیازهای یک PWA و مواردی که وبسایت شما اونها رو رعایت کرده یا در وبسایت وجود نداره بهتون تحویل میده.

شکل 2: نتیجه ی آنالیز سایت توسط پلاگین Lighthouse

این این لیست از سه بخش تشکیل شده:

  1. Fast and Reliable
  2. Installable
  3. PWA Optimized

در هر بخش لیستی از مواردی که باید pass شود تا وبسایت به یک PWA معتبر تبدیل بشه وجود داره. بیاید اونها رو بررسی کنیم.

1- Fast and Reliable:

سرعت در اجرای وبسایت و همچنین اجرای وبسایت در حالتی که کاربر آفلاین هست در این قسمت سنجیده میشه. در اینجا با نوشتن یک service worker و ساخت یک فایل manifest.json میتونیم موارد رو pass کنیم که در ادامه به توضیح این دو خواهیم پرداخت.

2- Installable:

در این قسمت بررسی میشه که آیا وبسایت ما به عنوان یک shortcut میتونه روی Home Screen کاربر قرار بگیره یا این امکان رو نداره. این موارد هم با نوشتن همان service worker و manifest.json قابل دسترس خواهد بود(که در ادامه شرح داده خواهد شد).

3- Optimized PWA:

در این قسمت مواردی برای نمایش تم‌ها روی دستگاه‌های مختلف، نمایش splash screen و همچنین برخی موارد کلی مورد نیاز برای اینکه وبسایت به یک PWA معتبر تبدیل بشه سنجیده خواهد شد. این موارد رو بعدا نام خواهیم برد که اکثرا شامل یکسری تگ HTML ساده در وبسایت شما میشه.

تبدیل یک وبسایت ساده به یک PWA

بیاید برای این قسمت از مقاله با مثال پیش بریم. فرض کنید وبسایت ساده‌ای داریم که شامل فایل‌های زیر میشه:

شکل 3: ساختار فایل های پروژه ی PWA
نکته: در نظر داشته باشید که در ادامه این مقاله انتظار میره که شما با javascript آشنایی داشته باشید.

در ادامه قصد داریم درباره ی دو موضوع صحبت کنیم. Service worker ها و manifest.json.

manifest.json:

اگر ساختار نرم‌افزارهای native پلتفرم‌ها رو دیده باشید (مانند اندروید)، شاید فایلی با نام manifest برای شما آشنا باشه. برای اینکه وبسایت ما به صورت یک اپلیکیشن عمل کنه نیاز به توضیحاتی در مورد این اپلیکیشن داریم. توضیحاتی مثل نام اپلیکیشن، نام نمایشی و آیکون اپلیکیشن که بر روی Home screen قرار میگیره (shortcut) ، فایل html ورودی اپلیکیشن هنگام باز شدن، جهت نمایش داده شدن اپلیکیشن (portrait/landscape)، تم نمایش اپلیکیشن و ... . این موارد رو در فایل manifest.json با فرمت json ذخیره میکنیم.
بیاید مهمترین مواردی رو که بهشون نیاز داریم بررسی کنیم:

  1. name: نام اپلیکیشن
  2. short_name: نام کوتاه شده اپلیکیشن برای نمایش در زمان‌های خاص
  3. start_url: فایل html ورودی اپلیکیشن
  4. display mode: نمایش در دستگاه مورد نظر (داخل مرورگر، full screen و ...)
  5. background_color: رنگ background قبل از load شدن فایل style
  6. orientation: جهت نمایش اپلیکیشن (portrait/landscape)
  7. icons: آرایه‌ای از آیکون ها برای نمایش در size های مختلف

لیست کامل این کلید‌ها رو میتونید اینجا مشاهده کنید.
برای اینکه PWA ما قابل نصب باشه باید یک فایل manifest.json بسازیم و در وبسایت خودمون وارد کنیم. این فایل رو در پروژه خودتون بسازید و کد زیر رو در فایل قرار بدید:

{
  "name": "Buy Share",
  "short_name": "Buy Share",
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#FFE9D2",
  "theme_color": "#FFE1C4",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/img/icons/icon-72x72.png",
      "type": "image/png",
      "sizes": "72x72"
    },
    // more icons with different sizes ...
  ]
}

دقت داشته باشید که در اینجا icons ، آرایه‌ای از آیکون‌ها رو قبول میکنه و باید برای سایزهای مختلف، آیکون‌های مختلفی رو تعریف کنید.
برای وارد کردن فایل manifest.json در پروژه کافیه از تگ link استفاده کنیم. تگ زیر مورد نیاز ما خواهد بود که در فایل index.html وارد میکنیم:

<link rel="manifest" href="manifest.json" />

بسیار عالی! اگر دوباره از lighthouse در کروم استفاده کنید میبینید که برخی از موارد pass شدن. همچنین اگر در Developer tools وارد تب application بشید میتونید manifest وبسایت خود رو مشاهده کنید. حالا که فایل manifest.json خودمون رو ساختیم میتونیم بریم سراغ service worker ها و این قابلیت مرورگرها رو بررسی کرده و ازشون استفاده کنیم.

Service workers:

شاید اسم service worker ها رو شنیده باشید و شاید هم با اونها کار کرده باشید. Service worker ها در واقع یک proxy در وبسایت ما هستند که به زبان جاوااسکریپت نوشته میشن. Service worker ها میتونند هر درخواستی که وبسایت ما لازم داره رو کنترل کنند، به درخواست یک پاسخ دلخواه و سفارشی شده بدن، جلوی درخواست رو بگیرن و ... . این به شما بستگی داره که چه انتظاری از service worker ها دارید.
در PWA ما میخوایم با استفاده از service worker ها تعدادی از assetهای وبسایت خودمون رو cache کنیم. همچنین میخوایم در صورتی که کاربر آفلاین بود، برخی از این اطلاعات کش شده ، برای کاربر نمایش داده بشه.
هر service worker برای اینکه در پروژه ما قرار بگیره باید در صفحه ما register بشه. همچنین هر service worker دارای eventهایی هست که در زمان register یا update شدن، رسیدن درخواست‌ها و ... فراخوانی میشن. 
متاسفانه service worker ها توسط نسخه‌های قدیمی مرورگرها پشتیبانی نمیشن و قبل از register شدن باید از پشتیبانی مرورگر از service worker و وجود این قابلیت در navigator مطمئن بشیم. میتونید از کد زیر برای بررسی پشتیبانی مرورگر از service worker استفاده کنید:

if ("serviceWorker" in navigator) {
  // do stuff
}

برای مشاهده لیست مرورگر‌هایی که از این ویژگی پشتیبانی میکنند اینجا کلیک کنید.
خب، حالا بیاید برای تکمیل PWA خودمون یک service worker در وبسایت خودمون قرار بدیم. ابتدا یک فایل js ساخته و در نظر داشته باشید که بعدا کدهای service worker رو در اون قرار خواهیم داد. ولی اول بیاید service worker ساخته شده رو در وبسایت خودمون register کنیم. برای این کار در فایل‌های html وبسایت در تگ script کد زیر رو وارد میکنیم(و یا یک فایل js ساخته و در فایل html وارد میکنیم):

if ("serviceWorker" in navigator) {
  navigator.serviceWorker
    .register("/serviceWorker.js")
    .then(reg => {
      console.log("Service worker registred successfully", reg);
    })
    .catch(err => {
      console.log("service worker not registred !!", err);
    });
}

دقت کنید در کد بالا ابتدا بررسی کردیم که آیا serviceWorker در navigator ما وجود داره یا نه. در صورتی که وجود نداشته باشه مرورگر ما از serviceworker پشتیبانی نخواهد کرد.
همچنین در نظر داشته باشید که متد register یک promise رو بر خواهد گردوند.
با این کار یک service worker در وبسایت خودمون register کردیم. حالا وارد فایل service worker خودتون بشید. کدهای زیر رو در فایل service worker که ساختید وارد کنید. در ادامه به توضیح این کدها خواهیم پرداخت:

const staticCacheName = "site-static-v1";
const cacheAssets = [
  "/",
  "/index.html",
  "/css/materialize.min.css",
  "/css/style.css",
  "/js/app.js",
  "/js/ui.js",
  "/js/materialize.min.js",
  "/img/dish.png",
  "./pages/fallback.html"
];

self.addEventListener("install", evt => {
  evt.waitUntil(
    caches
      .open(staticCacheName)
      .then(cache => {
        console.log("caching assets...");
        cache.addAll(cacheAssets);
      })
      .catch(err => {})
  );
});

self.addEventListener("fetch", evt => {
  evt.respondWith(
    caches
      .match(evt.request)
      .then(res => {
        return res || fetch(evt.request);
      })
      .catch(err => {
        if (evt.request.url.indexOf(".html") > -1) {
          return caches.match("./pages/fallback.html");
        }
      })
  );
});

در وبسایت خودمون قراره یکسری از assetها رو کش کنیم (که در حالت آفلاین نیز به این assetها دسترسی خواهیم داشت). برای راحتی کار، مسیر Asset هایی که قصد کش کردن داریم رو در آرایه cacheAssets قرار دادیم (این asset ها رو میتونید در ساختار پروژه در بالاتر آورده شد ببینید).
حالا بیاید در مورد دو event در service worker ها صحبت کنیم. ابتدا در نظر داشته باشید که در داخل service worker ها ، self به service worker اشاره میکنه.

  • Event اول install هست که بعد از register شدن service worker فراخوانی میشه. در این event توسط cache تمامی مواردی که میخوایم در cache storage ذخیره بشه رو اضافه میکنیم. ابتدا لیست کش با نام staticCacheName رو با استفاده از متد open میسازیم و سپس با استفاده از متد addAll ، آرایه cacheAssets رو کش میکنیم. حالا این موارد در cacheStorage مرورگر برای استفاده‌های بعدی کش میشوند. دقت کنید که ما این کار رو درون waitUntil انجام دادیم. استفاده از waitUntil باعث میشه تا زمانی که عملیات کش کردن تمام نشده ادامه کد اجرا نشه.
  • Event دوم fetch هست که بعد از هر درخواست فراخوانی خواهد شد. در این event با استفاده از متد respondWith درخواست رو بررسی میکنیم که اگر در cacheStorage وجود داشت، به جای اینکه asset رو دوباره دانلود کنه از cacheStorage به مرورگر بفرسته. همچنین در صورتی که درخواست به خطا بخوره (مثلا کاربر آفلاین باشه) در متد catch بررسی کردیم که فایل fallback.html رو برای حالت کاربر بفرسته که در cacheStorage قرار گرفته.

حالا میتونیم assetهای مورد نیاز رو کش کنیم و در حالت آفلاین در وبسایت استفاده کنیم.

نکته: دقت کنید که service worker ما زمانی که یکبار روی مرورگر register شد دوباره اجرا نخواهد شد. مگر تا زمانی که فایل service worker ما تغییر کنه که در این صورت service worker جدیدی روی مرورگر اجرا خواهد شد.
حالا مرورگر خودتون رو باز کنید. وارد وبسایت خودتون بشید. در Developer tools وارد تب application شده و در قسمت service worker نتیجه کار رو مشاهده کنید. میبینید که یک service worker در حال اجرا هست:

شکل 4: مشاهده ی Service Worker درحال اجرا

دوباره از lighthouse استفاده کنید. متوجه خواهید شد که برخی از موارد pass شدن.

برای مشاهده آشنایی بیشتر با service worker ها و event های اون‌ها میتونید از این لینک استفاده کنید.

چند نکته ی دیگر:

تا اینجا وبسایت شما باید installable و fast and reliable رو pass کرده باشه. تنها کافیه یکسری از موارد رو به پروژه اضافه کنید، وبسایت رو بر روی https سرو کنید و در نهایت هم درخواست‌های http رو به https ریدایرکت کنید تا PWA شما به طور کامل valid بشه.


مواردی مثل viewport، theme-color، apple-touch-icon (که در lighthouse به اون‌ها اشاره شده) با اضافه کردن تگ‌های HTML قابل دسترسی هستند. کافیه تگ‌های زیر رو در وبسایت خودتون قرار بدید:

<meta name=”viewport” content=”width=device-width, initial-scale=1.0” />
<meta name=”theme-color” content=”#FFE1C4”>
<link rel=”apple-touch-icon” href=”/img/icon/icon-192.png”>

اگر lighthouse رو دوباره اجرا کنید میبینید که تمامی موارد pass شدن و حالا ما یک PWA کامل داریم.

روی مرورگر گوشی این وبسایت رو باز کنید دیگه میتونید اون رو روی گوشی نصب کنید. اگر با chrome وبسایت رو باز کنید به شما یک پیام نشون داده میشه که میتونید این اپلیکیشن رو نصب کنید و بعد از نصب شدن، shortcut اون روی صفحه گوشی شما اضافه خواهد شد.

سخن پایانی:
در این مقاله سعی کردیم با PWA آشنا شده و این قابلیت رو به دست بیاریم تا وبسایت ساده خودمون رو به یک PWA تبدیل کنیم. مطمئنا مواردی بود که در این مقاله گنجانده نمیشد. میتونید به لینک‌های زیر برای بررسی موارد بیشتر مراجعه کنید:
Pwa checklist
Manifest.json 
Service workers

اگر سوالی دارید و یا درمورد PWAها تجربه ای دارید میتونید توی کامنت ها بهمون بگید. منتظر خواندن نظرات شما هستیم.

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس


online-support-icon