Alex Aung
Alex Aung

Reputation: 3159

Vite PWA background sync not working in React Typescript using vite-plugin-pwa

I am setting my react-typescript app into PWA mode. I use vite-plugin-pwa plugin. Step

  1. Load the page and will see the log (see the console logs)
  2. Then check the background sync. There is noting Under "Background Sync".
  3. Click Service Workers and check the Offline
  4. Then check the background sync. There is noting Under "Background Sync", I am ensure that sync tag (sync-animations) is not listed when offline.
  5. then uncheck offline
  6. Background sync function does not called.

May I know how to call background sync when I uncheck offline in browser or how to set up.

vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { VitePWA } from 'vite-plugin-pwa';

export default defineConfig({
  plugins: [
    react(),
    VitePWA({
      registerType: 'autoUpdate',
      strategies: 'injectManifest',
      srcDir: 'src',
      filename: 'serviceWorker.ts',
      includeAssets: [
        'favicon.ico',
        'robots.txt',
        'apple-touch-icon.png',
      ],
      manifest: {
        name: 'Lottie Animation Manager',
        short_name: 'LottieManager',
        description: 'Offline-First Lottie Animation Management System',
        theme_color: '#16A34A',
        background_color: '#ffffff',
        display: 'standalone',
        icons: [
          {
            "purpose": "maskable",
            "sizes": "512x512",
            "src": "icon512_maskable.png",
            "type": "image/png"
          },
          {
            "purpose": "any",
            "sizes": "512x512",
            "src": "icon512_rounded.png",
            "type": "image/png"
          }
        ],
      },
      workbox: {
        runtimeCaching: [
          {
            urlPattern: ({ request }) => request.destination === 'document',
            handler: 'NetworkFirst',
            options: {
              cacheName: 'documents',
              expiration: {
                maxEntries: 10,
              },
            },
          },
          {
            urlPattern: ({ request }) => request.destination === 'image',
            handler: 'CacheFirst',
            options: {
              cacheName: 'images',
              expiration: {
                maxEntries: 50,
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
              },
            },
          },
          {
            urlPattern: ({ request }) => request.destination === 'script' || request.destination === 'style',
            handler: 'StaleWhileRevalidate',
            options: {
              cacheName: 'static-resources',
              expiration: {
                maxEntries: 50,
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
              },
            },
          },
          {
            // Adjust the urlPattern to match your GraphQL endpoint
            urlPattern: /\/graphql/,
            handler: 'NetworkFirst',
            options: {
              cacheName: 'graphql-api',
              expiration: {
                maxEntries: 50,
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
              },
              networkTimeoutSeconds: 10,
            },
          },
          {
            urlPattern: /\/uploads\/.*\.json/,
            handler: 'CacheFirst',
            options: {
              cacheName: 'lottie-files',
              expiration: {
                maxEntries: 50,
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
              },
            },
          },
        ],
      },
    }),
  ],
});

main.ts

// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { registerSW } from 'virtual:pwa-register';

declare global {
  interface ServiceWorkerRegistration {
    sync: {
      register(tag: string): Promise<void>;
    };
  }
}

registerSW({
  onNeedRefresh() { console.log('SW: Need Refresh'); },
  onOfflineReady() {
    console.log('SW: Offline Ready');
    if ('serviceWorker' in navigator && 'SyncManager' in window) {
      navigator.serviceWorker.ready.then((registration) => {
        return registration.sync.register('sync-animations')
          .then(() => {
            console.log('Sync registration succeeded');
          })
          .catch((err) => {
            console.error('Sync registration failed:', err);
          });
      });
    }
  },
});

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

servieWorker.ts

/* eslint-disable @typescript-eslint/no-explicit-any */
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute, NavigationRoute } from 'workbox-routing';
import { createHandlerBoundToURL } from 'workbox-precaching';

declare let self: ServiceWorkerGlobalScope;

precacheAndRoute(self.__WB_MANIFEST);

self.addEventListener('install', () => {
  console.log('Service Worker: Installed');
  self.skipWaiting();
});

self.addEventListener('activate', (event) => {
  console.log('Service Worker: Activated');
  event.waitUntil(self.clients.claim());
});

self.addEventListener('sync', (event) => {
  console.log('Sync event received:', event);
  if ((event as any).tag === 'sync-animations') {
    console.log('Sync event: sync-animations');
    (event as any).waitUntil((async () => {
      console.log('Sync animations called');
    })());
  }
});

let allowlist: undefined | RegExp[];
if (import.meta.env.DEV) allowlist = [/^\/$/];

registerRoute(new NavigationRoute(createHandlerBoundToURL('index.html'), { allowlist }));

console logs

service Worker: Installed
SW: Offline Ready
Service Worker: Activated
Sync registration succeeded
Sync event received: SyncEvent {isTrusted: true, tag: 'sync-animations', lastChance: false, type: 'sync', target: ServiceWorkerGlobalScope, …}
Sync event: sync-animations
Sync animations called

Upvotes: 0

Views: 237

Answers (0)

Related Questions