pwa: Service worker not updating without force update

Hi,

I installed Vue PWA template and tested on Apache localhost with offline feature (Dev tool). It works as expected. I deployed same code to the production environment on Heroku. where it is not working as expected. Even when I reload the page old service worker is still running and cached version of app which I get in offline mode is stale. When I force update the service worker (From dev tool) then newer version of service worker is installed and only then it fetches fresh copy of project.

Here’s my production webpack config.

    new SWPrecacheWebpackPlugin({
      cacheId: 'my-vue-app',
      filename: 'service-worker.js',
      staticFileGlobs: ['dist/**/*.{js,html,css}'],
      minify: true,
      stripPrefix: 'dist/',
      mergeStaticsConfig: true, // if you don't set this to true, you won't see any webpack-emitted assets in your serviceworker config
      staticFileGlobsIgnorePatterns: [/\.map$/], // use this to ignore sourcemap files
    })

I have not changed service worker code in index.html

Is there anything I am missing?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 10
  • Comments: 32 (3 by maintainers)

Commits related to this issue

Most upvoted comments

particularly works exluding service-worker.js from cache

location = /service-worker.js {
    expires off;
    add_header Cache-Control no-cache;
    access_log off;
}
<filesMatch "service-worker\.js$">
FileETag None
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</filesMatch>

in this case I still have to clear browser cache and updates are available after second page reload.

Your problem is the caching header of the server for the service worker file. You need to set up your web server so the caching headers are set to 0. Currently your settings are: Cache-Control:max-age=31536000.

The caching headers on the service worker script are respected (up to 24 hours) when fetching updates. We’re going to make this opt-in behaviour, as it catches people out. You probably want a max-age of 0 on your service worker script. from: https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle#updates

2017-08-08 18_17_02-cst-poc

@kgrosvenor

service-worker only works in https mode.

@dvikas Yes, I changed to this and worked:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

<FilesMatch "service-worker.js$">
  Header set Cache-Control "max-age=0"
</FilesMatch>

I need to enable mod_headers in apache only, restart and enjoy 😃

If running express you can create a nocache middleware and apply it to where you send your index.html

function nocache () {
  return (req, res, next) => {
      res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
      res.header('Expires', '-1')
      res.header('Pragma', 'no-cache')
      next()
  }
}

router.get('/*', nocache(), (req, res) => res.sendFile(PATH_TO_ENTRY))

Just a heads up, if piping through cloudflare you need to toggle on respect existing headers under caching.

@rof20004 Yeah I know I’ll attach my nginx-configuration at the end of this post, but what I mean is that it sucks finding out about the worker-loader design of this template through github issues, this information should be made available on the front-page, as it is now we’ve gone live in production for 2 months and I have no clue how many customers got infected with an outdated service-worker or how to purge their cache-stores short of changing domain.

So yeah a heads-up that tells people to take extra care with the cache-settings in production would have been really appreciated back then. I will even go as far as stating that this issue is unresolved until a “PWA in production environment” chapter is available in the Readme.md. Alternatively information on how to entirely remove/disable the service worker for your project. Undocumented features are as bad as bugs.

Here’s my nginx tweak to achieve the same results:

location /service-worker.js {
  root   /app;
  add_header Last-Modified $date_gmt;
  add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
  if_modified_since off;
  expires off;
  etag off;
}

Please refer to Caching best practices & max-age gotchas - JakeArchibald.com It might be helpful to get you more understand about that.

@pushkardeshmukh1992 It seems that the issue isn’t involve to this pwa template directly. how about that close the issue?

@aleksandrmelnyk Hi,

I have this in my .htaccess(vue-router history mode for apache):

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

How can I integrate this code that you shared inside the same .htaccess, I tried this but not worked.

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

<Files index.html|service-worker.js>
    FileETag None
    Header unset ETag
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</Files>

Here is one for apache2:

<Files index.html|service-worker.js>
FileETag None
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</Files>

I used jakearchibald tips, for max-age: 0 to service-worker.js and works perfectly, when I update my code, the final user only needs to refresh the page, service-worker.js will do the job to cache all updates.

@pushkardeshmukh1992 Please follow below steps to debug the issue you are facing

  1. service-worker-prod.js Find this file in your app directory. It would be inside build folder.
  2. Line 33: Put console.log('new service worker installed') before break statement.
  3. Line 40 and Line 44: place console.log() with appropriate messages.
  4. Do let us know what you get.

Thanks.