GoogleChrome / workbox

📦 Workbox: JavaScript libraries for Progressive Web Apps
https://developers.google.com/web/tools/workbox/
MIT License
12.34k stars 814 forks source link

Precaching fails to cache JS on Firefox, but does so correctly on Chrome #3014

Closed kingfisher13 closed 2 years ago

kingfisher13 commented 2 years ago

Library Affected: workbox-precaching, workbox-webpack-plugin

Browser & Platform: Firefox v96

Issue or Feature Request Description: We're having an issue with Workbox. The codebase includes Workbox for PWA and caching support. On first load, Chrome will download the app files, and store them in the cache - this includes JS, CSS, and HTML. All working correctly.

Firefox, however, is only storing the CSS files. This makes it impossible to use the app offline on Firefox. Is this a bug or a problem with the code? I thought it was working before on Firefox, but I can't confirm that, so did an update (on either Workbox or FF) break it?

The exception for JS on FF, is the Cache.worker.js file, that is cached appropriately. Nothing else though.

The app is built with Vue. But I don't use the vue-cli-pwa as that was using an older version of Workbox. Instead, the vue.config.js uses workbox-webpack-plugin directly to compile the service worker.

vue.config.js file:

const CompressionPlugin = require('compression-webpack-plugin');
const { InjectManifest } = require('workbox-webpack-plugin');
module.exports = {
  chainWebpack: (config) => {
    config.module
      .rule('worker')
      .test(/\.worker\.js$/)
      .use('worker-loader')
      .loader('worker-loader')
      .end();
    // Exclude worker files from js compilation
    config.module.rule('js').exclude.add(/\.worker\.js$/);
    // Exclude the cache worker from worker compilation as it's compiled below with "InjectManifest"
    config.module.rule('worker').exclude.add(/Cache.worker\.js$/);
  },
  configureWebpack: {
    plugins: [
      // new CompressionPlugin(),
      new InjectManifest({
        maximumFileSizeToCacheInBytes: 4000000,
        swDest: 'Cache.worker.js',
        swSrc: './src/workers/Cache.worker.js'
      })
    ]
  }
};

Cache.worker.js file:

import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import {
  CacheFirst,
  StaleWhileRevalidate
} from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';
// When told to, promote the new SW over the old SW
self.addEventListener('message', (event) => {
  if (event.data === 'skipWaiting') {
    self.skipWaiting();
  }
});
// Precache files
precacheAndRoute(self.__WB_MANIFEST);
// Other caching happens below here, but isn't relevant to the precache

registerServiceWorker.js which is fired on App load:

import { register } from 'register-service-worker';
/**
 * Refresh site function
 * Returns a bound function bound to the SW itself
 */
function refresh(registration) {
  return function innerRefresh() {
    if (registration.waiting) registration.waiting.postMessage('skipWaiting');
  };
}
if (process.env.NODE_ENV === 'production') {
  register(`${process.env.BASE_URL}Cache.worker.js`, {
    error(error) {
      console.error('Error during service worker registration:', error);
    },
    updated(registration) {
      window.dispatchEvent(new CustomEvent('refresh', {
        detail: {
          refreshFunction: refresh(registration)
        }
      }));
    }
  });
}

The actual WB_Manifest includes all the JS/CSS/HTML required.

Everything works completely correctly on Chrome. I think it used to as well on Firefox, but not anymore. The Firefox cache is full of CSS files, but nothing else. The Chrome cache has the full suite of JS/HTML/CSS.

jeffposnick commented 2 years ago

I haven't heard of any similar reports. Our test suite runs against Firefox, among other browsers, and does cover this scenario.

Under the hood, precacheAndRoute(self.__WB_MANIFEST); will create an install handler and add all of the items in the precache manifest to a cache. A promise representing the successful completion of all these caching operations is passed to installEvent.waitUntil(), and if that promise rejects (because not everything was added to the cache), service worker installation will fail. So, if everything is behaving as expected per the service worker spec, you should never end up in a situation in which the service worker has successfully installed but there are items missing from the cache.

Could you pass along a link to a live URL which I could visit in Firefox to reproduce the issue?

kingfisher13 commented 2 years ago

I can't post it here, but happy to DM a link if that's an option?

jeffposnick commented 2 years ago

Sure—https://twitter.com/jeffposnick

jeffposnick commented 2 years ago

All of the resources appear to be cached in both Chrome and Firefox in the example web app you passed along.

That being said, you have 793 entries in your precache manifest, which is a lot. You should start with ensuring that .gz files aren't added to the precache manifest:

new InjectManifest({
  // ...other config...
  exclude: [/\.gz$/],
});

You can verify what's in the cache via commands in the JS console, since Firefox's cache storage viewer apparently won't show more than the first (50? 100? I didn't count) entries. All of those entries are CSS-related, so that might be why you thought that was all that was cached.

k = await caches.keys();
c = await caches.open(k[0]);
reqs = await c.keys();
reqs.forEach(r => console.log(r.url))
huykon commented 1 year ago

In my case concern it only show fail cache on chrome browser. You can check the site https://venia.magento.com/ image