Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precached page '/' not updating after new build is deployed #381

Closed
xrei opened this issue Oct 19, 2020 · 9 comments
Closed

Precached page '/' not updating after new build is deployed #381

xrei opened this issue Oct 19, 2020 · 9 comments

Comments

@xrei
Copy link

xrei commented Oct 19, 2020

Recently this problem appeared in our pwa. I had all default settings in workbox pwa module and everything worked fine, but now it seems root page (/) is precached, it is exists in CacheStorage workbox-precache-v2-...
After unregistering manually service worker this problem is gone, but only for the time before next page reload.
I can solve issue by manually deleting this CacheStorage, but it's not the solution because our users won't do it manually.

Question is, by which way sw can force delete this cache for all users ? Or is there a way to disable precache of this page? Maybe there is another way to solve this?

Also we have cloudflare cache, could it be a problem?

Also have this warning: Workbox is precaching URLs without revision info: / but updated pwa-module to the latest version.

@kedrzu
Copy link
Contributor

kedrzu commented Oct 21, 2020

I also encountered this problem.
I've read through source code and I don't think it's possible to fix it by ourselves - array of precached resources is built from webmanifest config and some defaults, which include / route.

Google docs say, that cache-first policy is used for precached resources, that's why page is not refreshed.
Precached resources are updated once service worker is, only if revision changes. And because no revision is used, it's not updating.

Maybe some randomized revision would help?

Problem is, that we may get some non-deterministic behavior - service worker is not updated immadietely, when you open the page. It may take some time, especially if you have other tabs open, that it controls. So you would get the old version until the service worker is running.

It would be nice to be able to fine-tune precaching, so we'd be able to remove / from precached resources.

@xrei
Copy link
Author

xrei commented Oct 21, 2020

Exactly the problem is because of / pushed to precache array. Currently there is no way to remove it. It must be fixed.

@kedrzu
Copy link
Contributor

kedrzu commented Oct 21, 2020

Ok guys, I have some temporary solution for ya!

Do not change default start_url in pwa.manifest:

pwa: {
    manifest: {
        orientation: 'portrait-primary',
        background_color: '#ffffff',
        theme_color: '#010101',
        start_url: '/', // <- this breaks the thing for me
        display: 'browser',
    },
},

By default it's /?standalone=true and that's good for you, because /?standalone=true will be precached, and not /.

@emilostervig
Copy link

I tried the fix proposed by @kedrzu which works for the start_url. It does not seem to clear the precache for the offlinePage template, which is a smaller issue but an issue still.

@kedrzu
Copy link
Contributor

kedrzu commented Nov 10, 2020

I created a PR with proposed fix, but it's not merged yet. In my own project I created my own sw.template.js file:

const options = <%= JSON.stringify(options.swOptions) %>

importScripts(...[options.workboxURL, ...options.importScripts])

initWorkbox(workbox, options)
workboxExtensions(workbox, options)
cachingExtensions(workbox, options)
runtimeCaching(workbox, options)
offlinePage(workbox, options)
routingExtensions(workbox, options)

function getProp(obj, prop) {
  return prop.split('.').reduce((p, c) => p[c], obj)
}

function initWorkbox(workbox, options) {
  if (options.config) {
    // Set workbox config
    workbox.setConfig(options.config)
  }

  if (options.cacheNames) {
    // Set workbox cache names
    workbox.core.setCacheNameDetails(options.cacheNames)
  }

  if (options.clientsClaim) {
    // Start controlling any existing clients as soon as it activates
    workbox.core.clientsClaim()
  }

  if (options.skipWaiting) {
    workbox.core.skipWaiting()
  }

  if (options.cleanupOutdatedCaches) {
    workbox.precaching.cleanupOutdatedCaches()
  }

  if (options.offlineAnalytics) {
    // Enable offline Google Analytics tracking
    workbox.googleAnalytics.initialize()
  }
}

function runtimeCaching(workbox, options) {
  for (const entry of options.runtimeCaching) {
    const urlPattern = new RegExp(entry.urlPattern)
    const method = entry.method || 'GET'

    const plugins = (entry.strategyPlugins || [])
      .map(p => new (getProp(workbox, p.use))(...p.config))

    const strategyOptions = { ...entry.strategyOptions, plugins }

    const strategy = new workbox.strategies[entry.handler](strategyOptions)

    workbox.routing.registerRoute(urlPattern, strategy, method)
  }
}

function offlinePage(workbox, options) {
  if (options.offlinePage) {
    // Register router handler for offlinePage
    workbox.routing.registerRoute(new RegExp(options.pagesURLPattern), ({ request, event }) => {
      const strategy = new workbox.strategies[options.offlineStrategy]
      return strategy
        .handle({ request, event })
        .catch(() => caches.match(options.offlinePage))
    })
  }
}

function workboxExtensions(workbox, options) {
  <%= options.workboxExtensions %>
}

function cachingExtensions(workbox, options) {
  <%= options.cachingExtensions %>
}

function routingExtensions(workbox, options) {
  <%= options.routingExtensions %>
}

It's exactly same as original https://github.com/nuxt-community/pwa-module/blob/master/lib/workbox/templates/sw.js, but it lacks the part responsible for precaching.

Then added in config:

workbox: {
    swTemplate: './sw.template.js',
    // other settings
}

@Anima-t3d
Copy link

Seems to be caused when trying to fix this issue: #372

@Anima-t3d
Copy link

I used this code on the loading screen as a workaround (unregister service worker and hard reload to use new serviceWorker):

  function reloadApp() {
    if (window.location.hash !== '#retry') {
      window.location.hash = '#retry';
      window.location.reload(true);
    } else {
      /* Workaround failed, inform user */
      setLoadingMessage('An error occurred');
    }
  }

  window.addEventListener('error', function (event) {
    if ('serviceWorker' in navigator) {
      /* Prepare for unregister serviceWorker and reload, inform user */
      setLoadingMessage('Updating...');

      navigator.serviceWorker.getRegistrations().then(function(registrations) {
        registrations.forEach(function(r) {
          r.unregister();
        });
        reloadApp();
      });
    } else {
      /* Could not try workaround, inform user */
      setLoadingMessage('An error occurred');
    }
  });

setLoadingMessage() just updates the UI.

@pi0
Copy link
Member

pi0 commented Nov 28, 2020

Hi. This issue should be gone with 3.3.0.

@pi0
Copy link
Member

pi0 commented Nov 30, 2020

There is yet one more known issue tracking here: #406

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants