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

Service worker not updating without force update #70

Closed
pushkardeshmukh1992 opened this issue Aug 8, 2017 · 32 comments
Closed

Service worker not updating without force update #70

pushkardeshmukh1992 opened this issue Aug 8, 2017 · 32 comments

Comments

@pushkardeshmukh1992
Copy link

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?

@sushant-j
Copy link

@LinusBorg @addyosmani - Any suggestions?

@sushant-j
Copy link

Here's a link to video, showing service worker not being updated on page reload.
(It shows service worker #198 installing, but disappears without actually installing it.)

@sandrosc
Copy link

sandrosc commented Aug 8, 2017

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

@devmedoo
Copy link

devmedoo commented Aug 16, 2017

I can reproduce the same issue, the browser simply loads the old version that the service worker installed first time and doesn't get updated.
I tried forcing hash regeneration by commenting the corresponding lines in webpack config, but no luck sadly.
@sandrosc I've tried forcing max-age=0 for files(in httpd.conf) but it doesn't seem to fix the issue for me.

@ragingwind
Copy link
Contributor

ragingwind commented Aug 17, 2017

Serviceworker should be updated as follow the guide https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle#updates, if serviceworker has different content(bytes) and server-side certainly can deliver newer version of servicewoker to client-side.

I recommend that first check out server side always could serve a newer version of service worker by requests in browser because of there are many reason to counteract updates assets like cache-control. and then track the process of installing server worker via self.addEventListener('install') to see what happens in installing process

@pushkardeshmukh1992
Copy link
Author

I tried both nginx and apache configuration to unset caching headers. Didn't work as expected.

Then finally decided to go with Vue Template because didn't want to get into caching issues on production.

@anubhav7495
Copy link
Collaborator

@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.

@aleksandrmelnyk
Copy link

yep, same issue here.
Added console.logs to ervice-worker-prod.js , but nothing appeared in console

Had to manually remove SW cache an d clean cookies.
2017-08-21_1220

@aleksandrmelnyk
Copy link

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.

@pushkardeshmukh1992
Copy link
Author

@aleksandrmelnyk I will re-try with this particular nginx config. Thanks!

@ragingwind
Copy link
Contributor

ragingwind commented Aug 23, 2017

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?

@rof20004
Copy link

rof20004 commented Sep 8, 2017

I am with the same problem, in mobile I do not have a clear cache button in browser, someone knows how to correct?

@radar155
Copy link

I think it's a bad idea to cache index.html. js and css files have a different hash name every time you build them with some changes. If you don't cache index.html, you will fetch a fresh version of it every time and that fresh version will include new js and css files with new names.
If there are no change to your css or js assets, you will simply use your cache.
Then, for offline first experience, is better (only for index.html) to implement Network falling back to the cache

@rof20004
Copy link

rof20004 commented Sep 13, 2017

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.

@flybayer
Copy link

Default behavior of sw-precache is to load resources from cache, them update the cache in the background. Next time you refresh the page, the browser will load the updated resources from cache.

This Stackoverflow answer explains how to have better UX for the update:
https://stackoverflow.com/a/40130378/1356531

@aleksandrmelnyk
Copy link

It works fine for me, when I disabled index.html from cache

@ahus1
Copy link
Contributor

ahus1 commented Nov 5, 2017

This is what worked for me - out sample project is here: https://github.com/dukecon/dukecon_pwa

To the template we added two things:

  1. set cache header for all resources (at things in the static folder shouldn't be cached indefinitely)
  2. updated service-worker-prod.js with a window.location.reload(); to reload the page once a new version is available

Ad 1: we're using Apache httpd with a .htaccess file with the following contents:
Header set Cache-Control "max-age=300, must-revalidate"

Ad 2: if a new version is available, this leads to a reload of the page some seconds after the user loaded the page. This works for us, but might not work for everyone else.

Side note: we changed the setting of "staticFileGlobs" in webpack.prod.conf.js to ['dist/**/*.{js,html,css,png,gif,svg,ico}'] - the original version didn't include images and icons.

Suggestion:

  • README.md should describe the no-caching policy one should configure on the web server
  • README.md should describe the change necessary in inside service-worker-prod.js
  • webpack.prod.conf.js should include also graphics and icons.

Please comment - I'm happy to create a PR for this.

@telamon
Copy link

telamon commented Nov 13, 2017

I've run into the same issue but i'm on a template version from september, A summary of optimal production cache-settings should really be included in the README.md - the serviceworker is basically just a giant pitfall as it is right now.

Is there any way to quickly just disable this caching-feature for production?

@rof20004
Copy link

@telamon You can control cache in server-side, this is what I did and worked, I set max-age=0 for service-worker.js file.

@telamon
Copy link

telamon commented Nov 14, 2017

@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;
}

@aleksandrmelnyk
Copy link

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>

@rof20004
Copy link

@telamon I aggree with completly.

jeffposnick added a commit that referenced this issue Nov 27, 2017
add section why cache limitation is necessary with examples #70
@camwhite
Copy link

camwhite commented Mar 1, 2018

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
Copy link

rof20004 commented Jun 15, 2018

@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>

@dvikas
Copy link

dvikas commented Jun 20, 2018

@rof20004 did you tried this in .htaccess

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

# BEGIN Cache-Control Headers
<ifModule mod_headers.c>
  <filesMatch "(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"
  </filesMatch>
</ifModule>

@rof20004
Copy link

@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 :)

@kgrosvenor
Copy link

kgrosvenor commented Nov 22, 2018

I've done all of the above, this is my nginx config
Do i need pragma as well ?

  location ~ (index.html|service-worker.js)$ {
      add_header Last-Modified $date_gmt;
      add_header Cache-Control 'no-cache, no-store, must-revalidate, proxy-revalidate, max-age=300';
      if_modified_since off;
      expires off;
      proxy_no_cache 1;
      etag off;
   }

This solves things half way for me

Sometimes when i build my websites, different machine provide a white screen and the manifest.js / app.js results in a 404 which of course it doesn't exist anymore because now there is a new one, anyway only when i refresh the page i get the latest build, other times it builds and refreshes when i access and installs the update successfully .

If i witness the previous build in the browser, and wait for my pipeline to finish its ok, successful, when i get home to check on my laptop that is two builds behind i get a white screen, i've tried everything so far.

Any ideas?

@rof20004
Copy link

rof20004 commented Jan 4, 2019

@kgrosvenor

service-worker only works in https mode.

@manuelmejiaio
Copy link

Any solution for cloudflare?

@rof20004
Copy link

@mejiamanuel57 in fact, you only need to remove the cache from service-worker.js file.

Maybe this can help you:
https://support.cloudflare.com/hc/en-us/articles/200172316-How-do-I-exclude-a-specific-URL-from-Cloudflare-s-caching-

@manuelmejiaio
Copy link

Hi, Thank you @rof20004 I follow this tutorial:
https://rossta.net/blog/adding-serviceworker-to-a-simple-website.html

Creating a page rule for the service workers works.

@hugomallet
Copy link

Hi, why do you disable etag ?

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

No branches or pull requests