Skip to content

Cached SW index.html gets a 404 error on old bundle #3882

Closed
@robertvansteen

Description

@robertvansteen

Is this a bug report?

Yes

Did you try recovering your dependencies?

Yes, happened on multiple deployments.

Which terms did you search for in User Guide?

Read the parts about service worker and also searched for similar issues, found this one: #3613 but that was about chunking, which I do not use.

Environment

  1. node -v: 9.4.0
  2. npm -v: 5.6.0
  3. yarn --version (if you use Yarn): 1.3.2
  4. npm ls react-scripts (if you haven’t ejected): n/a

Then, specify:

  1. Operating system: Mac OS High Sierra
  2. Browser and version (if relevant): Google Chrome 63

Expected Behavior

When I deploy a new version of my application I expect it to load the old HTML and load the old JS bundle from it's cache. If that's no longer available (for whatever reason) it should fetch the new HTML and with that also the new JS bundle.

Actual Behavior

The service worker serves the old index.html, but it tries to get the JS bundle from the server. Because a new version has been deployed that bundle is no longer there, so it receives a 404 error, resulting in a white (broken) page. Refreshing the page fixes the issue.

The contents of my index.js

// @flow
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';

import Organisation from './apps/organisation';

const release = process.env.REACT_APP_GIT_COMMIT;

// Set up Sentry
if (process.env.NODE_ENV !== 'development') {
  window.Raven.config(
    'https://secret@sentry.io/secret',
    { release },
  ).install();
}

console.log(`Commit: ${String(release)}`);

const element = document.getElementById('root');

if (element) {
  ReactDOM.render(<Organisation />, element);
}

registerServiceWorker();

Here screenshots of the network tab during the 'broken state'

screen shot 2018-01-21 at 00 57 49

screen shot 2018-01-21 at 00 58 10

Activity

gaearon

gaearon commented on Jan 21, 2018

@gaearon
Contributor
robertvansteen

robertvansteen commented on Jan 21, 2018

@robertvansteen
ContributorAuthor

Here is an example of a generated service-worker.js

"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}var precacheConfig=[["/index.html","babecb6373fb7c685cc0703542f7702a"],["/static/css/main.9d5e9b4c.css","22c6c6d0a3679263956373d2eb40ce7d"],["/static/media/animation.9d17f3ac.gif","9d17f3ace48d33e1b362a766acb2d3ad"],["/static/media/animation.aae0d6dc.gif","aae0d6dced7a545e75f416fbbc4dfdcc"],["/static/media/info.d9f5a737.png","d9f5a737db51e7036bd1c27571f79fe7"],["/static/media/logo.8757bc3d.svg","8757bc3d40ff0e229060296b42759cdf"],["/static/media/logoFull.e546045c.svg","e546045c3646e22270ffad8fe10f8ed0"],["/static/media/logoFullNegative.ab027f8d.svg","ab027f8d4aef8a4bf3593e2dde3bf68f"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(e){if(!e.redirected)return Promise.resolve(e);return("body"in e?Promise.resolve(e.body):e.blob()).then(function(t){return new Response(t,{headers:e.headers,status:e.status,statusText:e.statusText})})},createCacheKey=function(e,t,n,r){var a=new URL(e);return r&&a.pathname.match(r)||(a.search+=(a.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),a.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,t){var n=new URL(e);return n.hash="",n.search=n.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),n.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],r=new URL(t,self.location),a=createCacheKey(r,hashParamName,n,/\.\w{8}\./);return[r.toString(),a]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(n){if(!t.has(n)){var r=new Request(n,{credentials:"same-origin"});return fetch(r).then(function(t){if(!t.ok)throw new Error("Request for "+n+" returned a response with status "+t.status);return cleanResponse(t).then(function(t){return e.put(n,t)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(n){return Promise.all(n.map(function(n){if(!t.has(n.url))return e.delete(n)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,n=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);(t=urlsToCacheKeys.has(n))||(n=addDirectoryIndex(n,"index.html"),t=urlsToCacheKeys.has(n));!t&&"navigate"===e.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],e.request.url)&&(n=new URL("/index.html",self.location).toString(),t=urlsToCacheKeys.has(n)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}});

As you can see there is no .js bundle there.

This is what the build process logged:

File sizes after gzip:

  399.47 KB  build/static/js/main.10cf50b4.js
  3.64 KB    build/static/css/main.9d5e9b4c.css
robertvansteen

robertvansteen commented on Jan 21, 2018

@robertvansteen
ContributorAuthor

I tried a few more things and it seems like when I comment out some code it does gets included in the SW precache list. But it's not a particular piece of code, so it looks like it's related to the file size. The current size is far below the maximum default size in SWPrecache (which is 2MB) and as far as I can tell CRA doesn't change that limit.

jeffposnick

jeffposnick commented on Jan 23, 2018

@jeffposnick
Contributor

Here are some "odd" things that your screenshots/code snippets illustrate which I'd like to get to the bottom of:

  • There are three requests for index.html from within the service worker shown in your Network Panel screenshot, but there's only one reference to /index.html in your precacheConfig. (This might be a red herring, but it's odd to see.)
  • As you say, there's no reference at all to your .js files in the precacheConfig. Using a cached version of index.html without a corresponding cached entry for the .js would lead to version mismatches that you're seeing.

You may be on the right track regarding size limits, as sw-precache will, by default, not precache any resource whose actual size, uncompressed, is above 2mb. Your log messages indicate that the compressed size of main.10cf50b4.js is 399.47kb, and I could easily imagine the uncompressed size being over 2mb. Can you confirm that? (There's normally a build-time message logged about resources that are too large to precache, but that's disabled in create-react-app.)

robertvansteen

robertvansteen commented on Feb 2, 2018

@robertvansteen
ContributorAuthor

@jeffposnick I'm not sure how I can see the unminified file size with create-react-app but I can confirm that code splitting fixed this problem. I think it's a good thing that large files are not downloaded for offline usage but it would be good to show the message if the file size is too large. I now have to manually check the service-worker.js before deploying to make sure that all chunks are in there because if they don't my site breaks on the next deployment.
@gaearon would it be possible to show that message?

jeffposnick

jeffposnick commented on Feb 2, 2018

@jeffposnick
Contributor

It's going to get trickier to justify showing the logged output from the sw-precache plugin in the future because service worker registration isn't going to be on by default. So you'd end up with a scenario in which there were warning messages being logged corresponding to a feature that a developer isn't actually making use of.

robertvansteen

robertvansteen commented on Feb 2, 2018

@robertvansteen
ContributorAuthor

Maybe it could be a general warning like “hey be warned your bundle (or chunk) is big (and will not be cached for offline use if you use a service worker), consider splitting it in multiple chunks to improve load time” or something

jeffposnick

jeffposnick commented on Feb 8, 2018

@jeffposnick
Contributor

FWIW, I found #2612 which effectively tracks the same request (and is closed).

RohovDmytro

RohovDmytro commented on Feb 16, 2018

@RohovDmytro

Had same issue. As it referenced I've outline some thought here. #3574

Stas-Buzunko

Stas-Buzunko commented on May 17, 2018

@Stas-Buzunko

@rogovdm i'm using firebase hosting as well and facing the same problem, have you fixed it?

Shpadoinkle

Shpadoinkle commented on Jun 12, 2018

@Shpadoinkle

yep same here. Have tried adding header caching rules to the header section with no success.

Currently trying to unregister the serviceWorker but this seems like a horrid way to get around this bug.

I swear this used to work just fine. So not sure where the issue began.

But judging on the history of react devs and how often issue threads just close down due to inactivity, I doubt this will be addressed any time soon.

samanmohamadi

samanmohamadi commented on Jun 14, 2018

@samanmohamadi

I have the same problem.
updating sw from chrome dev tools will refresh index.html.

sh00ter

sh00ter commented on Jun 20, 2018

@sh00ter

Any update on this or the only real solution is to opt-out of caching?

robertvansteen

robertvansteen commented on Jun 20, 2018

@robertvansteen
ContributorAuthor

@sh00ter the solution is code splitting. See one of my comments above.

sh00ter

sh00ter commented on Jun 20, 2018

@sh00ter

@rovansteen I am using Loadable to split the code but I guess that one of the chunks is still large enough not to be picked up by the service worker.

robertvansteen

robertvansteen commented on Jun 20, 2018

@robertvansteen
ContributorAuthor

@sh00ter yeah unfortunately there is no warning or anything like that to see if one of the bundles is too big so we do this by manually checking it.

robertvansteen

robertvansteen commented on Jun 20, 2018

@robertvansteen
ContributorAuthor

But you could implement something like this to automate that process: #2612 (comment)

Stas-Buzunko

Stas-Buzunko commented on Aug 21, 2018

@Stas-Buzunko

#3882 (comment)

solution worked for me

nfantone

nfantone commented on Oct 4, 2018

@nfantone

@Timer I hit this very same issue today after deployment using latest CRA 2.0.4 and the new Workbox service worker script.

image

Manually unregistering the worker and refreshing makes the site load, but any subsequent refreshes just crashes it again for me.

Used to work just fine with previous versions, mind you (sw-precache).

I believe this issue should be re-opened.

EDIT
For what I've been gathering around, this seems to be related to chunk sizes - however, my app's chunks are actually quite small:

  294.54 KB  build/static/js/1.7199b771.chunk.js
  49.06 KB   build/static/js/main.2c86934a.chunk.js
  21.38 KB   build/static/css/main.ff66eee3.chunk.css
  1.6 KB     build/static/css/1.fdfa198a.chunk.css

As you can see from the names of the chunks resulting from the build and the ones being fetched from the worker (screenshot), service-worker.js tries to load a different version every time (cc. @jeffposnick)

I'm at a loss here, at the moment.

Timer

Timer commented on Oct 4, 2018

@Timer
Contributor

Please file a new issue if you believe you're experiencing a bug.

locked and limited conversation to collaborators on Jan 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @sh00ter@nfantone@Timer@gaearon@RohovDmytro

        Issue actions

          Cached SW index.html gets a 404 error on old bundle · Issue #3882 · facebook/create-react-app