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

Improve logging when Chrome's offline check fails #2749

Closed
StanzillaManticore opened this issue Feb 10, 2021 · 29 comments · Fixed by #2777
Closed

Improve logging when Chrome's offline check fails #2749

StanzillaManticore opened this issue Feb 10, 2021 · 29 comments · Fixed by #2777
Labels
Developer Experience Related to ease of use for developers. workbox-strategies

Comments

@StanzillaManticore
Copy link

StanzillaManticore commented Feb 10, 2021

Welcome! Please use this template for reporting bugs or requesting features. For questions about using Workbox, the best place to ask is Stack Overflow, tagged with [workbox]: https://stackoverflow.com/questions/ask?tags=workbox

Library Affected: workbox
workbox-sw, workbox-build, etc.

Browser & Platform: Google Chrome 89
E.g. Google Chrome v51.0.1 for Android, or "all browsers".

Issue or Feature Request Description: Uncaught (in promise) TypeError: Failed to fetch

My start_url is set to /?utm_source=web_app_manifest&utm_medium=web_app_manifest&utm_campaign=web_app_manifest

When reporting bugs, please include relevant JavaScript Console logs and links to public URLs at which the issue could be reproduced.

image

image

It also errors when deployed on a https url

My config looks like this:

import { skipWaiting, clientsClaim } from "workbox-core"
import {
  cleanupOutdatedCaches,
  precacheAndRoute,
  matchPrecache,
} from "workbox-precaching"
import { setCatchHandler } from "workbox-routing"
import { registerRoute } from "workbox-routing"
import {
  NetworkFirst,
  StaleWhileRevalidate,
  CacheFirst,
} from "workbox-strategies"
import { CacheableResponsePlugin } from "workbox-cacheable-response"
import { ExpirationPlugin } from "workbox-expiration"
import * as googleAnalytics from "workbox-google-analytics"

googleAnalytics.initialize()

cleanupOutdatedCaches()
precacheAndRoute(self.__WB_MANIFEST)
clientsClaim()

function cacheKeyWillBeUsed({ request }) {
  const url = new URL(request.url)
  url.pathname = url.pathname.replace(/\/index\.html$/, "/")
  url.pathname = url.pathname.replace(/\.html$/, "/")
  return url.href
}

const networkFirstStrategy = new NetworkFirst({
  cacheName: "docs-cache",
  fetchOptions: {
    credentials: "include",
  },
  plugins: [{ cacheKeyWillBeUsed }],
})

// Cache page navigations (html) with a Network First strategy
registerRoute(
  // Check to see if the request is a navigation to a new page
  ({ request }) => request.mode === 'navigate',
  // Use a Network First caching strategy
  new NetworkFirst({
    // Put all cached files in a cache named 'pages'
    cacheName: 'pages',
    plugins: [
      // Ensure that only requests that result in a 200 status are cached
      new CacheableResponsePlugin({
        statuses: [200],
      }),
      cacheKeyWillBeUsed
    ],
  }),
);

// Cache CSS, JS, and Web Worker requests with a Stale While Revalidate strategy
registerRoute(
  // Check to see if the request's destination is style for stylesheets, script for JavaScript, or worker for web worker
  ({ request }) =>
    request.destination === 'style' ||
    request.destination === 'script' ||
    request.destination === 'worker',
  // Use a Stale While Revalidate caching strategy
  new StaleWhileRevalidate({
    // Put all cached files in a cache named 'assets'
    cacheName: 'assets',
    plugins: [
      // Ensure that only requests that result in a 200 status are cached
      new CacheableResponsePlugin({
        statuses: [200],
      }),
    ],
  }),
);

registerRoute(
  /\.(?:png|jpg|jpeg|svg|gif|ico|mp4)$/,
  // Use the cache if it's available.
  new CacheFirst({
    cacheName: "image-cache",
    fetchOptions: {
      credentials: "include",
    },
    plugins: [
      new ExpirationPlugin({
        // Cache only 50 images.
        maxEntries: 50,
        // Cache for a maximum of a day.
        maxAgeSeconds: 24 * 60 * 60,
      }),
    ],
  })
)

// Cache the Google Fonts stylesheets with a stale-while-revalidate strategy.
registerRoute(
  ({ url }) => url.origin === "https://fonts.googleapis.com",
  new StaleWhileRevalidate({
    cacheName: "google-fonts-stylesheets",
  })
)

// Cache the underlying font files with a cache-first strategy for 1 year.
registerRoute(
  ({ url }) => url.origin === "https://fonts.gstatic.com",
  new CacheFirst({
    cacheName: "google-fonts-webfonts",
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxAgeSeconds: 60 * 60 * 24 * 365,
        maxEntries: 30,
      }),
    ],
  })
)

// Catch routing errors, like if the user is offline
setCatchHandler(async ({ event }) => {
  // Return the precached offline page if a document is being requested
  if (event.request.destination === "document") {
    return matchPrecache("/offline.html")
  }

  return Response.error()
})

addEventListener("message", (event) => {
  if (event.data && event.data.type === "SKIP_WAITING") {
    skipWaiting()
  }
})
@jeffposnick
Copy link
Contributor

Apologies, but I need a bit more information to determine how to help.

Are you posting this because you don't expect there to be a request automatically made for your start_url, and you're curious as to why it's being logged in the Network panel? If so, it's probably due to https://developer.chrome.com/blog/improved-pwa-offline-detection/

@jeffposnick jeffposnick added the Needs More Info Waiting on additional information from the community. label Feb 10, 2021
@StanzillaManticore
Copy link
Author

I'm curious as to why it shows up as an error, yes.

@jeffposnick
Copy link
Contributor

So that's why the request is being made in the first place. In terms of why the request results in an error, are you precaching your /index.html or / URL? If not, and you're just relying on that request.mode === 'navigate' route, I'm assuming the reason it fails is because the /?utm_source=web_app_manifest&utm_medium=web_app_manifest&utm_campaign=web_app_manifest isn't in the cache at the time it's tested.

/ will be added to the cache during subsequent visits, by virtue of that runtime caching route, but it won't be added with all of those query parameters. So you should either add matchOptions: {ignoreQuery: true} to your strategy to tell the Cache Storage API to ignore those parameters when performing a match, or alternatively, modify the cacheKeyWillBeUsed plugin you're already using in that strategy to drop the query parameters.

If you were precaching / or /index.html, then I would expect that initial offline check to pass, since the precache routing logic ignores utm_.* parameters when looking for matches by default.

@StanzillaManticore
Copy link
Author

StanzillaManticore commented Feb 11, 2021

I am indeed not precaching / or /index.html, would you say that adding that is the better path here or rather the matchOptions version?

@jeffposnick
Copy link
Contributor

It depends! If you precache /index.html, it will be served with a cache-first strategy and won't be updated until the service worker lifecycle allows the latest service worker to take over. If your priority is showing a fresh /index.html each time a user returns your web app, then it won't be a good idea to precache it.

Using the new warmStrategyCache() method in workbox-recipes would be an easy way to ensure that /index.html is cached during service worker installation, without relying on precaching. And then at that point, you can either use cacheKeyWillBeUsed or matchOptions: {ignoreQuery: true} to handle the URL query parameters—since you already have a cacheKeyWillBeUsed that's doing some manipulation, it's probably cleaner to just do that.

Putting it all together, and leaving out the bits not related to the navigations:

import {warmStrategyCache} from 'workbox-recipes';
import {NetworkFirst} from 'workbox-strategies';
import {registerRoute} from 'workbox-routing';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';

function cacheKeyWillBeUsed({request}) {
  const url = new URL(request.url);
  url.pathname = url.pathname.replace(/\/index\.html$/, "/");
  url.pathname = url.pathname.replace(/\.html$/, "/");
  // Clear out all search params.
  url.search = '';
  return url.href;
}

const navigationStrategy = new NetworkFirst({
  cacheName: 'pages',
  plugins: [
    new CacheableResponsePlugin({
      statuses: [200],
    }),
    cacheKeyWillBeUsed,
  ],
});

registerRoute(
  ({request}) => request.mode === 'navigate',
  navigationStrategy
);

warmStrategyCache({
  urls: ['/'],
  strategy: navigationStrategy,
});

@StanzillaManticore
Copy link
Author

@jeffposnick So I tried that, full code here:

import { warmStrategyCache } from "workbox-recipes"
import { skipWaiting, clientsClaim } from "workbox-core"
import { cleanupOutdatedCaches, precacheAndRoute, matchPrecache } from "workbox-precaching"
import { registerRoute, setCatchHandler } from "workbox-routing"
import { NetworkFirst, StaleWhileRevalidate, CacheFirst } from "workbox-strategies"
import { CacheableResponsePlugin } from "workbox-cacheable-response"
import { ExpirationPlugin } from "workbox-expiration"
import * as googleAnalytics from "workbox-google-analytics"

googleAnalytics.initialize()

cleanupOutdatedCaches()
precacheAndRoute(self.__WB_MANIFEST)
clientsClaim()

function cacheKeyWillBeUsed({ request }) {
  const url = new URL(request.url)
  url.pathname = url.pathname.replace(/\/index\.html$/, "/")
  url.pathname = url.pathname.replace(/\.html$/, "/")
  // Clear out all search params.
  url.search = ''
  return url.href
}

const navigationStrategy = new NetworkFirst({
  cacheName: 'pages',
  plugins: [
    new CacheableResponsePlugin({
      statuses: [200],
    }),
    cacheKeyWillBeUsed,
  ],
});

registerRoute(
  ({ request }) => request.mode === 'navigate',
  navigationStrategy
);

warmStrategyCache({
  urls: ['/'],
  strategy: navigationStrategy,
});

// Cache CSS, JS, and Web Worker requests with a Stale While Revalidate strategy
registerRoute(
  // Check to see if the request's destination is style for stylesheets, script for JavaScript, or worker for web worker
  ({ request }) =>
    request.destination === 'style' ||
    request.destination === 'script' ||
    request.destination === 'worker',
  // Use a Stale While Revalidate caching strategy
  new StaleWhileRevalidate({
    // Put all cached files in a cache named 'assets'
    cacheName: 'assets',
    plugins: [
      // Ensure that only requests that result in a 200 status are cached
      new CacheableResponsePlugin({
        statuses: [200],
      }),
    ],
  }),
);

registerRoute(
  /\.(?:png|jpg|jpeg|svg|gif|ico|mp4)$/,
  // Use the cache if it's available.
  new CacheFirst({
    cacheName: "image-cache",
    fetchOptions: {
      credentials: "include",
    },
    plugins: [
      new ExpirationPlugin({
        // Cache only 50 images.
        maxEntries: 50,
        // Cache for a maximum of a day.
        maxAgeSeconds: 24 * 60 * 60,
      }),
    ],
  })
)

// Cache the Google Fonts stylesheets with a stale-while-revalidate strategy.
registerRoute(
  ({ url }) => url.origin === "https://fonts.googleapis.com",
  new StaleWhileRevalidate({
    cacheName: "google-fonts-stylesheets",
  })
)

// Cache the underlying font files with a cache-first strategy for 1 year.
registerRoute(
  ({ url }) => url.origin === "https://fonts.gstatic.com",
  new CacheFirst({
    cacheName: "google-fonts-webfonts",
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxAgeSeconds: 60 * 60 * 24 * 365,
        maxEntries: 30,
      }),
    ],
  })
)

// Catch routing errors, like if the user is offline
setCatchHandler(async ({ event }) => {
  // Return the precached offline page if a document is being requested
  if (event.request.destination === "document") {
    return matchPrecache("/offline.html")
  }

  return Response.error()
})

addEventListener("message", (event) => {
  if (event.data && event.data.type === "SKIP_WAITING") {
    skipWaiting()
  }
})

But this would still cause the fetch failure, even after clearing all data and installing fresh.

fetch("http://127.0.0.1:8000/?utm_source=web_app_manifest&utm_medium=web_app_manifest&utm_campaign=web_app_manifest", {
  "referrer": "",
  "referrerPolicy": "unsafe-url",
  "body": null,
  "method": "GET",
  "mode": "cors",
  "credentials": "omit"
});

@jeffposnick jeffposnick reopened this Feb 11, 2021
@jeffposnick
Copy link
Contributor

Hmm... do you happen to have this deployed to a public URL at which I could check it out live? Feel free to DM @jeffposnick on Twitter if you can't share it in a public issue.

@StanzillaManticore
Copy link
Author

Yes, I can! This is currently deployed on https://development.docs.coregames.com/

@jeffposnick
Copy link
Contributor

This took a while to figure out until I tried it out in a TypeScript project, at which point it identified the following mistake:

const navigationStrategy = new NetworkFirst({
  cacheName: 'pages',
  plugins: [
    new CacheableResponsePlugin({
      statuses: [200],
    }),
    {cacheKeyWillBeUsed}, // <--- this needed to be surrounded by {} 
  ],
});

Can you try again with those missing {}?

I am still trying to figure out exactly why there might be even a one-time failure to fetch that page when Chrome automatically checks for offline capabilities, but that fix should at least (I hope) make the cache fallback work for real navigations to your start_url.

@StanzillaManticore
Copy link
Author

I deployed a new version with that change but it looks like the fetch still fails :(

@jeffposnick
Copy link
Contributor

I was having a really hard time understanding why I was seeing your offline.html page instead of your index page when manually navigating to https://development.docs.coregames.com/?utm_source=web_app_manifest&utm_medium=web_app_manifest&utm_campaign=web_app_manifest while offline. And the {cacheKeyWillBeUsed} at least explains that!

But yes, the automatic fetch that Chrome performs that's described at https://developer.chrome.com/blog/improved-pwa-offline-detection/ is still failing. I am now wondering if it might be related to #2744, which includes a change to the way some of the asynchronous NetworkFirst logic operates.

I'd like to see if, once #2744 is merged and we cut the next Workbox release, that error from the automatic offline detection is still logged. In the meantime, I don't think it should actually affect the functionality of your web app—offline capabilities when you navigate "for real" are working.

@jeffposnick jeffposnick added workbox-strategies and removed Needs More Info Waiting on additional information from the community. labels Feb 11, 2021
@StanzillaManticore
Copy link
Author

I updated to 6.1.1 today after I saw that the PR was merged but it looks like it still errors. Updated version is at the same URL as above.

@jeffposnick
Copy link
Contributor

Sorry for the delay in getting back to you.

I think that everything is working as "expected," but unfortunately it is a bit confusing now that the automatic offline navigation detection fires off a navigation request for your start_url with the network simulated as offline.

I realize that you're seeing the request failure message logged just because that's what happens when you use a NetworkFirst runtime strategy and you're offline—there's an exception thrown when the network request fails, even though a valid response ends up being provided from the cache. So the installability criteria is met, but there's an error logged.

This came up in another GitHub issue recently, and I guess it's more likely to cause confusion now that the automatic offline navigation detection is fired off by Chrome.

I'm going to leave this issue open to track some work that we could do to improve the logging around a failed network request when using NetworkFirst, just to make it clearer that the response is eventually provided. I'm also going to follow-up with the team at Chrome responsible for the automatic offline navigation detection to see if it might be possible to provide better attribution somewhere in DevTools letting developers know that the request is associated with that detection.

@jeffposnick jeffposnick changed the title Failed to fetch on start_url Improve logging when network fails, but there's a cache hit Mar 3, 2021
@jeffposnick jeffposnick added the Developer Experience Related to ease of use for developers. label Mar 3, 2021
@stashdjian
Copy link

stashdjian commented Mar 4, 2021

We also started seeing "Failed to Fetch" ghost requests errors with Chrome 89 release starting yesterday. These are coming from the new PWA installability checks as reported by Jeff. This is being done to prove that a website that claims to be installable through reporting a link rel="manifest" is really capable of delivering content while offline. So if you page is not reporting a manifest file, you'll not get this error reproduced.

I was working earlier to try to get rid of the error message in console, which is misleading, but couldn't get rid of it. Using a StaleWhileRevalidate strategy to cache the root path is getting the new PWA installability check passing, but the strategy tries to revalidate the file using the original request (which is designed to fail) and throws the error.

I couldn't find documentation or an easy way to detect this type of Request and avoid trying to send it to network or use it to update cache. It would be nice to have a flag or similar on the Request object indicating it is designed to fail.

@jeffposnick
Copy link
Contributor

This gets a big tough to track down to all the async code, but ultimately, when there's an Uncaught (in promise) TypeError: Failed to fetch message logged, despite the fact that the Strategy (NetworkFirst or StaleWhileRevalidate) is able to generate a response from the cache, it comes from the throw error at the end of

try {
await handler.runCallbacks('handlerDidRespond', {
event,
request,
response,
});
await handler.doneWaiting();
} catch (waitUntilError) {
error = waitUntilError;
}
await handler.runCallbacks('handlerDidComplete', {
event,
request,
response,
error,
});
handler.destroy();
if (error) {
throw error;
}

@philipwalton touched this code most recently, and I'm honestly not sure what the impact would be if the error were not thrown at this point, or only thrown when response is false-y, like

 if (error && !response) { 
   throw error; 
 } 

What do you think, Phil?

@philipwalton
Copy link
Member

In addition to the code highlighted above, there's also console noise (e.g. red error messages) from this code:

logger.error(`Network request for `+
`'${getFriendlyURL(request.url)}' threw an error.`, error);

I think we'd have to find a way to avoid both if we want to not scare developers into thinking something is wrong (when it isn't). Experimenting locally, when I comment out both error logging/throwing, my site doesn't emit any scary console messages from the offline check.

@philipwalton touched this code most recently, and I'm honestly not sure what the impact would be if the error were not thrown at this point...

I think we could potentially remove the re-throw. I remember not being sure about this when I was implementing it, and I chose to keep it to help make sure developers didn't have errors in their caching logic (or something like that).

If a developer wants to know if their waitUntil() code throws, they can check for an error property passed to the handlerDidComplete callback. (Though they have to be looking for that, it won't be made obvious in devtools.)

@philipwalton
Copy link
Member

Thinking about this a bit more (and playing with a few options in the code), I don't think we need (or want) to remove the rethrow in the _awaitComplete() method.

The problem currently (upon further investigation) is that the fetch error is even making its way to the _awaitComplete() method in the first place. I think this is happening because in StrategyHandler#fetch() we add the response promise to this.waitUntil().

fetch(input: RequestInfo): Promise<Response> {
return this.waitUntil((async () => {

I remember I originally chose to do this because I wanted to mimic the fact that event.respondWith() adds the response promise to the extendible event lifetime promise set. But the side effect of doing this is any error thrown as part of generating the response will also make its way into _awaitComplete() method.

I think we don't actually need to pass the response promise in either the fetch() or the catchMatch() method of the StrategyHandler class. Instead, we should only be calling this.waitUntil() for promises that aren't part of generating the response (e.g. adding a response to the cache after it's returned).

When I try removing the this.waitUntil() bit from the fetch() method, the error doesn't make its way to the _awaitComplete() method.

However, even if we do this we'll still need to address the error logged here (as mentioned above):

logger.error(`Network request for `+
`'${getFriendlyURL(request.url)}' threw an error.`, error);

@phil-w
Copy link

phil-w commented Mar 11, 2021

I hit the same error with a home-grown service-worker and came to "workbox" in the hope it would be over it already.

I don't get the scary red messages in Firefox. Alternatively removing the site's manifest (!) avoids generating the messages.

@jeffposnick
Copy link
Contributor

jeffposnick commented Mar 11, 2021

Thanks for looking into this, @philipwalton.

Regarding the development build logging messages, I think that's okay, as we also log additional info about how we're falling back to the cache:

if (process.env.NODE_ENV !== 'production') {
if (response) {
logs.push(`Got response from network.`);
} else {
logs.push(`Unable to get a response from the network. Will respond ` +
`with a cached response.`);
}
}

If folks are using the development build, I think there's enough info about what's going on that they can at least determine that the request was ultimately successful, even if we log that network failure. I'm more concerned about folks using production builds, who just see the logged exception without any other context.

Regarding that exception, your suggestion about only explicitly waiting on promises that aren't used for generating a response sounds good, but also sounds like a breaking change, so that might need to wait until Workbox v7.

What I'm thinking for v6 is to decorate the exception message to at least provide some context, like:

if (error) {
  if (response) {
    const message = `A response was generated for ${request.url} ` +
        `and this error can be ignored: ${error.message}`;
    throw new Error(message);
  }

  throw error;
}

(Exact wording to be decided.)

@jeffposnick
Copy link
Contributor

And we can also change that logger.error() in StrategyHandler.ts to a logger.info() to make it clearer that it might not ultimately be a failure.

@jeffposnick
Copy link
Contributor

I made both those changes in a local copy of Workbox used on https://so-pwa.firebaseapp.com/, and this is what ultimately is logged in the console when the automatic offline check takes place:

Screen Shot 2021-03-11 at 9 59 30 AM

This is still not "great" in that there's some red logged, but at least there's context. (It's a little noisy because the URL is long, unfortunately.)

@jeffposnick
Copy link
Contributor

Also, I wanted to let folks know that separate from the issue of how Workbox logs things, we are actively working with the Chrome DevTools team to provide more context about what's going on during the automatic offline check. Those improvements would help developers regardless of whether they're using Workbox or not.

@jeffposnick jeffposnick changed the title Improve logging when network fails, but there's a cache hit Improve logging when Chrome's offline check fails Mar 11, 2021
@jeffposnick
Copy link
Contributor

After chatting with @philipwalton about this, I think the consensus is that making the change outlined in #2749 (comment) falls more into the category of "bug fix for unintended behavior" than "breaking change of documented API" so we should be able to get it out sooner in the next Workbox v6 release.

@Alex-Golovin
Copy link

Alex-Golovin commented Mar 13, 2021

Hi @jeffposnick , my app have similar issue.

https://songbook.app/en?standalone=true - while this page URL is already in cache - workbox still throws an error that it can't fetch this url.

Screenshot 2021-03-13 at 20 05 10

I've tried to add it to runtime cache using axios get request and also directly adding it to cache like this:

if ('serviceWorker' in navigator) {
      window.addEventListener('load', function() {
        caches.open('sb-runtime-cache-v1').then(function(cache) {
          cache.match('/en?standalone=true').then(function(response) {
            if (!response) {
              cache.add('/en?standalone=true')
            }
          })
        })

        navigator.serviceWorker.register('/sw.js', {
          scope: '/'
        })
      })
    }

Could you help to figure out how to fix this issue?

Previously I've added this url to cache using axios get request and it worked, now it's broken, I believe after google "improved offline check".
If I use precache - all good, but I need it in runtime cache because I need to refresh response in cache after user signed in to app.
LMK if have to provide more details.

@jeffposnick
Copy link
Contributor

This should be resolved in https://github.com/GoogleChrome/workbox/releases/tag/v6.1.2

@StanzillaManticore
Copy link
Author

Awesome, thank you!

@shadowwalker
Copy link

CC: @jeffposnick

Hi all, after some digging and testing. I found an INTERESTING way to pass new offline check in Chrome properly.

With workbox 6.1.2, this issue is mitigated by not logging the failed fetch as an error to console. Which is good so that you are not bombed with this red error message and don't know what you should do. But it appears the Network tab in development tools still shows as an failed fetch network request under simulated offline scenario.

My solution will completed remove that failed network request in Network tab, implementation in next-pwa is here:

https://github.com/shadowwalker/next-pwa/blob/3dfda13890a00b297ad171ee9122f623b4e6f848/index.js#L246

runtimeCaching.unshift({
  urlPattern: basePath,
  handler: 'NetworkFirst',
  options: {
    cacheName: 'start-url',
    expiration: {
      maxEntries: 1,
      maxAgeSeconds: 24 * 60 * 60 // 24 hours
    },
    networkTimeoutSeconds: 10,
    plugins: [{
      // mitigate Chrome 89 auto offline check issue
      // blog: https://developer.chrome.com/blog/improved-pwa-offline-detection/ 
      // issue: https://github.com/GoogleChrome/workbox/issues/2749
      // I know this seems dummy, but it does the trick by gain some time for the cache to be ready :)
      requestWillFetch: async ({request}) => (Request(), request)
    }]
  }
})

Note the requestWillFetch plugins callback is doing nothing but returning same request passed in, but before that it create a Request object and throw away.

My guess is that due to some asynchronous magic, this delays the offline check request in Chrome 89+ a bit, so that cache will be ready to serve that request.

So what you should do if you are not using next-pwa. You can create a runtimeCaching config or registerRoute with the same plugins requestWillFetch configured, then you should have same result.

@jeffposnick
Copy link
Contributor

Hello @shadowwalker—I'd very much suggest not attempting to avoid DevTools noise via that approach. There's overhead in re-creating the request, and I don't really understand what's going on that would cause it to lead to different logs being displayed.

The Chrome team has heard the feedback from this thread and elsewhere, and rolled back the automatic offline check, starting with Chrome 90. Stay tuned for updates to the public guidance. The check may be reinstated at some point in the future, but the developer experience will be taken into account in anything that gets reimplemented.

Thanks for everyone's patience regarding this in the meantime!

@Yashs911
Copy link

@jeffposnick I am using both offlineFallback for offline page and warmStrategyCache to fetch the URL without visiting the page and using runtime caching but even after the HTML for that URL is cached I am seeing the offline page.

// Offline Page
setDefaultHandler(
  new NetworkOnly()
);

offlineFallback({
  pageFallback: '/static/offline.html',
  imageFallback: '/static/images/blank.book.lg.png'
});

function matchFunction({ url }) {
  const pages = ['/', '/account/login', '/account', '/account/books', '/account/loans', '/account/books/already-read/stats'];
  return pages.includes(url.pathname);
}

// runtime caching as the user visits the page
registerRoute(
  matchFunction,
  new NetworkFirst({
    cacheName: 'html-cache',
    plugins: [
      new ExpirationPlugin({
        // Keep at most 50 entries.
        maxEntries: 50,
        // Don't keep any entries for more than 30 days.
        maxAgeSeconds: 30 * 24 * 60 * 60,
        // Automatically cleanup if quota is exceeded.
        purgeOnQuotaError: true,
      }),
      // only cache if it the request returns 0 or 200 status
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
    ],
  })
);

const strategy = new CacheFirst();
const urls = [
  '/account/login',
];

warmStrategyCache({urls, strategy});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Developer Experience Related to ease of use for developers. workbox-strategies
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants