How do I cache other routes for offline browsing?
Asked Answered
E

3

7

I am setting up a Progressive Web App supporting offline browsing.

I have already set up offline browsing for my main route ('domainsample.com/') and it responds 200 even if offline.

But when I navigate to other routes ('domainsample.com/about') I receive a No Internet Page error.

Here is a sample I deployed in Heroku the URL: https://pwa-hehe.herokuapp.com

I used Vue CLI 3 to set up the project and Node.js and Express.js to run my dist folder in the server.

// server.js
const express = require('express')
const path = require('path')
const history = require('connect-history-api-fallback')

const app = express()

const staticFileMiddleware = express.static(path.join(__dirname + '/dist'))

app.use(staticFileMiddleware)

app.use(history({
    disableDotRule: true,
    verbose: true
}))

app.use(staticFileMiddleware)

app.get('/', function (req, res) {
    res.render(path.join(__dirname + '/dist/'))
})

var server = app.listen(process.env.PORT || 3000, function () {
    var port = server.address().port
    console.log("App now running on port", port)
})
// manifest.json
{
  "name": "pwa-offline",
  "short_name": "pwa-offline",
  "icons": [
    {
      "src": "./img/icons/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "./img/icons/android-chrome-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start_url": "./index.html",
  "display": "standalone",
  "background_color": "#000000",
  "theme_color": "#4DBA87"
}

// service-worker.js

/**
 * Welcome to your Workbox-powered service worker!
 *
 * You'll need to register this file in your web app and you should
 * disable HTTP caching for this file too.
 * 
 *
 * The rest of the code is auto-generated. Please don't update this file
 * directly; instead, make changes to your Workbox build configuration
 * and re-run your build process.
 * 
 */

importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js");

importScripts(
  "/precache-manifest.d3f1ce5d8331bddc555348f44cfba9d8.js"
);

workbox.core.setCacheNameDetails({prefix: "pwa-offline"});

/**
 * The workboxSW.precacheAndRoute() method efficiently caches and responds to
 * requests for URLs in the manifest.
 * 
 */
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
Elle answered 2/10, 2019 at 8:46 Comment(3)
Where did you define the offline strategy? I see only your web manifest, but no service worker's code.Ashlieashlin
Hi, edited the question, I am only using the auto generated service-worker.js from Vue CLI 3, i believe i should make my own?Elle
May I ask if any of the answers worked, or if you found a solution?Unreflecting
C
3

There's a simpler solution that doesn't involve using InjectManifest.

Simply add this to your vue.config.js file:

pwa: {
  workboxOptions: {
    navigateFallback: 'index.html'
  }
}

It will automatically add the necessary code to your service worker:

workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("index.html"));

I had the same problem and I found the solution here: https://github.com/vuejs/vue-cli/issues/717#issuecomment-382079361

Cabby answered 18/12, 2019 at 10:11 Comment(0)
E
1

To anyone who is also using the vue/cli-pligin-pwa and vue-cli 3, I have solved this problem.

The vue/cli-pligin-pwa does its job in caching your js files for offline use of your web app.

but since you're using a Single Page App, you'll have to set a some kind of fallback.

The request for the page e.g.(sample.com/about) will be a navigation request and it will serve the cached page for /index.html

Source: https://developers.google.com/web/tools/workbox/modules/workbox-routing#how_to_register_a_navigation_route

So what I did is, I made a custom service worker by entering this line of code in my vue.config.js file

// vue.config.js

module.exports = {
    pwa: {
        // configure the workbox plugin
        workboxPluginMode: 'InjectManifest',
        workboxOptions: {
            swSrc: 'public/service-worker.js'
        }
    }
}

and now, create a service-worker.js in your public folder directory, and write up the the generated line of codes from vue/cli-pligin-pwa and add the line : workbox.routing.registerNavigationRoute('/index.html');

//service-worker.js

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

workbox.routing.registerNavigationRoute('/index.html');

// install new service worker when ok, then reload page.
self.addEventListener("message", msg => {
    if (msg.data.action == 'skipWaiting') {
        self.skipWaiting()
    }
})
Elle answered 22/10, 2019 at 4:19 Comment(0)
A
0

The problem is that your service worker is not aware of which assets to cache. What is the value of self.__precacheManifest? (probably the web manifest file).

You would need to configure workbox in order to have some assets for the precacheAndRoute method, as this will instruct the service worker on which files to cache and when. Something like:

workbox.precaching.precacheAndRoute([
  '/styles/example.ac29.css',
  '/app/offlinePage.js',
  '/app/offlinePage.html',
  // ... other entries ...
]);

Per default a service worker does not know which assets or HTTP responses to cache, therefore we have to define and implement a caching strategy according to our requirements.

I wrote an article about service workers and the available caching strategies. Have a look at it if you want to deepen the topic.

Ashlieashlin answered 2/10, 2019 at 11:11 Comment(2)
hi, i will look in to that article, i believe i also need a bit more research with workbox and service worker before i integrate it in vue.js, thanks!Elle
If the answer helped you going on or answered your question, you should mark it as resolved. +1 eventually if you learnt something from it.Ashlieashlin

© 2022 - 2024 — McMap. All rights reserved.