dg.run

نصب و کار کردن آفلاین: انتخاب با شماست

بازار به برنامه شما یک نشانی اختصاصی می‌دهد و فایل‌های شما را همان‌جا ارائه می‌کند. داشتن manifest یا service worker الزامی نیست و برنامه‌ها با برچسب «قابل نصب» یا «آفلاین کار می‌کند» علامت‌گذاری نمی‌شوند. اگر می‌خواهید برنامه‌تان قابل نصب باشد، آفلاین کار کند، یا صفحه‌ای نشان دهد که کاربر را به نصب دعوت می‌کند، خودتان آن را در برنامه می‌سازید. در این صورت، آن را روی صفحه خودتان به کاربران بگویید.

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

چرا هر برنامه زیردامنه خودش را دارد

هر برنامه روی زیردامنه خودش اجرا می‌شود که یک مبدأ (origin) جداگانه در مرورگر است. برنامه شما فضای ذخیره‌سازی (IndexedDB و localStorage) و service worker مخصوص خودش را دارد و کاملاً از برنامه‌های دیگر جداست. هیچ برنامه‌ای نمی‌تواند داده‌های برنامه دیگر را بخواند. پیشنهاد نصب هم فقط به برنامه شما تعلق دارد.

اگر می‌خواهید قابل نصب باشد

نصب یک قابلیت مرورگر است و از فایل‌های شما دو چیز می‌خواهد که هر دو فایل معمولی داخل بسته شما هستند:

  • یک manifest وب که با <link rel="manifest" href="/manifest.webmanifest"> از صفحه‌هایتان به آن پیوند داده می‌شود، با نام، start_url، scope، display: "standalone" و آیکون‌ها (۱۹۲ و ۵۱۲ پیکسل)؛
  • یک service worker (مثلاً sw.js در سطح بالای بسته تا دامنه‌اش کل برنامه را بپوشاند) که با navigator.serviceWorker.register('/sw.js') در کد شما ثبت می‌شود. کار کردن آفلاین هم به همین وابسته است.

ابزارهایی مثل vite-plugin-pwa هر دو را برایتان می‌سازند. اگر برنامه شما manifest داشته باشد، بازار نام، توضیح، آیکون و برچسب‌های آن را هم برای فهرست به کار می‌برد. این تنها چیزی است که از آن می‌خواند.

صفحه معرفی و برنامه در پوشه‌های جدا

الگویی که خوب جواب می‌دهد: یک صفحه معرفی در ریشه نشانی شما که از بازدیدکننده می‌خواهد نصب کند، و خود برنامه در پوشه‌ای مثل /app.

  • صفحه / نام برنامه، کارش و یک دکمه نصب را نشان می‌دهد. دکمه رویداد beforeinstallprompt مرورگر را نگه می‌دارد و با فشرده شدن prompt() را صدا می‌زند. جایی که مرورگر چنین رویدادی ندارد (مثلاً Safari روی iPhone و iPad)، صفحه توضیح می‌دهد چطور دستی نصب شود.
  • manifest مقدار "start_url": "/app" و "scope": "/" دارد. برنامه نصب‌شده همیشه /app را باز می‌کند؛ پس کسانی که نصب کرده‌اند هرگز صفحه معرفی را نمی‌بینند و کسانی که نصب نکرده‌اند به نصب دعوت می‌شوند.
  • وقتی صفحه معرفی داخل پنجره برنامه نصب‌شده باز شد (matchMedia('(display-mode: standalone)'))، آن را مستقیم به /app بفرستید.

پوشه examples/market-pwa در مخزن یک نمونه کامل است، با service worker واقعی، آیکون‌ها و روند نصبی که در مرورگر آزمایش شده است.

اگر می‌خواهید آفلاین کار کند

service worker فایل‌های شما را ذخیره می‌کند تا برنامه بدون شبکه باز شود. فراخوانی‌های بک‌اند پلتفرم (/_dg/) همیشه به اتصال نیاز دارند؛ پس یک نسخه محلی از آنچه کاربر نیاز دارد نگه دارید و هیچ چیز زیر /_dg/ را ذخیره نکنید.

ارائه به‌روزرسانی

بازار sw.js، index.html و manifest را در هر بارگذاری دوباره اعتبارسنجی می‌کند؛ پس نسخه تأییدشده بدون ترفند کش به مرورگرها می‌رسد. مرورگرها هنگام اجرا یا پیمایش و تا یک بار در روز، تا وقتی برنامه باز می‌ماند، service worker جدید را بررسی می‌کنند. برای فهمیدن به‌روزرسانی در برنامه نصب‌شده‌ای که از قبل باز است، هنگام برگشت به پیش‌زمینه از ثبت‌نام بخواهید دوباره بررسی کند:

navigator.serviceWorker.ready.then((registration) => {
  document.addEventListener('visibilitychange', () => {
    if (document.visibilityState === 'visible' && navigator.onLine) void registration.update()
  })
})

در هر build چیزی را در service worker تغییر دهید (مثلاً نام کشی که هش فایل‌هایتان را دارد) تا مرورگرها نسخه جدید را ببینند. هرگز خود sw.js را کش نکنید، وگرنه به‌روزرسانی‌ها تشخیص داده نمی‌شوند. اگر برنامه service worker ندارد، چون index.html دوباره اعتبارسنجی می‌شود، فایل‌های جدید را در بارگذاری بعدی می‌گیرد.

پیش از ثبت آزمایش کنید

  • build را محلی ارائه دهید و در Chrome باز کنید. در DevTools پنل Application manifest و service worker را نشان می‌دهد و Lighthouse گزارش می‌دهد که برنامه قابل نصب است یا نه.
  • در DevTools شبکه را روی Offline بگذارید و صفحه را دوباره بارگذاری کنید: برنامه باید همچنان باز شود.
  • یادتان باشد ذخیره‌سازی به مبدأ وابسته است؛ پس داده‌های آزمایش محلی شما به نشانی‌تان در بازار منتقل نمی‌شود.