Can a service worker built with Google's sw-precache really be networkFirst?

caching, javascript, progressive-web-apps, service-worker, sw-precache

Solution

When generating service-workers, the easiest way to get the policy you want, is by using `sw-precache` with `sw-toolbox`.

When generating a new service-worker with`sw-precache`, you can also get the `sw-toolbox` code at the end of the generated file by passing the correct configuration options.

According to the sw-precache Documentation:

The `sw-precache` module has the ability to include the `sw-toolbox` code and configuration alongside its own configuration. Using the `runtimeCaching` configuration option in `sw-precache` (see below) is a shortcut that accomplishes what you could do manually by importing `sw-toolbox` in your service worker and writing your own routing rules.

This is an example of the `runtimeCaching` option showed on the `sw-precache` documentation:

runtimeCaching: [{
  urlPattern: /^https:\/\/example\.com\/api/,
  handler: 'networkFirst'
}, {
  urlPattern: /\/articles\//,
  handler: 'fastest',
  options: {
    cache: {
      maxEntries: 10,
      name: 'articles-cache'
    }
  }
}]

You can use this option alongside your configuration of choice.

For example you can use a configuration file as stated in the documentation:

There's support for passing complex configurations using --config . Any of the options from the file can be overridden via a command-line flag. We strongly recommend passing it an external JavaScript file defining config via module.exports. For example, assume there's a path/to/sw-precache-config.js file that contains:

module.exports = {
  staticFileGlobs: [
    'app/css/**.css',
    'app/**.html',
    'app/images/**.*',
    'app/js/**.js'
  ],
  stripPrefix: 'app/',
  runtimeCaching: [{
    urlPattern: /this\\.is\\.a\\.regex/,
    handler: 'networkFirst'
  }]
};

That file could be passed to the command-line interface, while also setting the verbose option, via

$ sw-precache --config=path/to/sw-precache-config.js --verbose

This provides the most flexibility, such as providing a regular expression for the runtimeCaching.urlPattern option.

Or you can use a JSON file:

We also support passing in a JSON file for --config, though this provides less flexibility:

{
  "staticFileGlobs": [
    "app/css/**.css",
    "app/**.html",
    "app/images/**.*",
    "app/js/**.js"
  ],
  "stripPrefix": "app/",
  "runtimeCaching": [{
    "urlPattern": "/express/style/path/(.*)",
    "handler": "networkFirst"
  }]
}

This example uses the JS file for the configuration options:

$ sw-precache --config=path/to/sw-precache-config.js --verbose

After executing the command and generating the service-worker with this configurations, you can handle the precache and policies much easier than with just `sw-precache`.

You can configure your policies directly in the file or add them manually at the bottom of your service-worker code.

Here is the example of the bottom part of the generated code:

//sw-precache generated code...

// *** Start of auto-included sw-toolbox code. ***
/*
 Copyright 2016 Google Inc. All Rights Reserved.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/ 
//(!function(e){if("object"==typeof exports&&"undefined"!=typeof module))...

// *** End of auto-included sw-toolbox code. ***

// Runtime cache configuration, using the sw-toolbox library.

toolbox.router.get(/this\\.is\\.a\\.regex/, toolbox.networkFirst, {});

toolbox.options.debug = true;

//Here you can configure your precache:

toolbox.precache([
    '/',
    '/assets/background.png',
    '/assets/logo.png',
    '/assets/application.css',
]);

//And here you can configure your policies for any route and asset:

toolbox.router.get('/', toolbox.fastest);
toolbox.router.get('/assets/background.png', toolbox.fastest);
toolbox.router.get('/assets/logo.png', toolbox.fastest);

//Here is the Network First example

toolbox.router.get('/myapp/index.html', toolbox.networkFirst);

I've found this much more effective and flexible than using just `sw-precache`.

Here you can find the sw-toolbox Usage Guide for more info on the configuration.

Problem

I run the website https://www.igluonline.com running Hugo and I recently installed a service worker following Google's sw-precache. This is the Config file: ``` module.exports = { staticFileGlobs: [ 'dist/css/**.css', 'dist/**/*.html', 'dist/images/**.*', 'dist/js/**.js' ], skipWaiting: true, stripPrefix: 'dist', runtimeCaching: [{ urlPattern: /\/*/, handler: 'networkFirst' }] }; ``` Considerations: Although sometimes the automatic generated code runs into some erros, the service worker works properly and deliver the offline experience both on web and mobile. Also it has `cache-control` set to `max-age=0` and when I push a new code it makes the update. Problem: I set the `runtimeCaching handler` to `networkFirst` and according to Google's `sw-toolbox` API (which is present in `sw-precache` when using `runtimeCaching`) it should get the page preferably from the http call and if there is no connection it should fallback to the cache. But when I refresh my code and open a new window to test (note that I do close all tabs and windows running the website prior to the update), it will show the cached page. It will naturally download the new service worker and on second reload update the page, but I don't expect my visitors to double refresh my homepage every time to get new content. I try changing the `runtimeCaching`code to the following hoping to get at least my homepage to load directly from the network, but I had no luck: ``` runtimeCaching: [{ urlPattern: /\//, handler: 'networkOnly' },{ urlPattern: /\/*/, handler: 'networkFirst' }] ``` Now I'm not sure if the desired PWA experience is like that - meaning that users have to reload twice or at least visit two pages to see the refreshed code - or if I'm making some mistake. I'd really appreciate a consideration.

Original source

Related problems