Pwa-module: Compatibility with Workbox Webpack InjectManifest Plugin

Created on 11 Apr 2019  Â·  18Comments  Â·  Source: nuxt-community/pwa-module

What problem does this feature solve?

If I'm not mistaken it is currently neither possible to dynamically add assets bundled by webpack to the preCache with out of the box Nuxt PWA features nor is it possible to integrate the Worbox Webpack InjectManifest Plugin (https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin).
It would be great if either of those two options would be implemented, to allow pre-caching files dynamically generated by webpack.

This feature request is available on Nuxt community (#c128)
feature-request

Most helpful comment

Another +1 request for adding this as optional functionality in v3 if possible please - for my current use case, precaching all assets on load is the central reason for building as a PWA. Thanks!

All 18 comments

Hi. This was default behavior with v2. Starting with v3, webpack plugin removed to reduce downloaded assets. Instead, they will be automatically cached on the fly. Chunks and assets for the next page will be also prefetched by nuxt-link.

It would be great if there was on option to precache assets in v3 too.
It is really useful for providing a "download" button to prepare everything for offline use.

I would like to somehow add this functionality again. But it was problematic for general use cases where it was causing everything to be downloaded as soon as service worker is registered. I'll keep this issue open to see what we can do :)

Any updates on this topic? Want to precache some routes in my nuxt spa

maybe i’m misunderstanding the new configuration settings. But the ‘on the fly caching’ is not the same as precaching as far as mine understanding goos. What would be the workaround with the new version of this package?

Another +1 request for adding this as optional functionality in v3 if possible please - for my current use case, precaching all assets on load is the central reason for building as a PWA. Thanks!

It would be great to see pre-caching all assets added back in for v3 :)

A workaround I'm using for dynamic routes in my nuxt.config.js is, assuming I have pages/topics/_slug.vue. The other routes I'm adding manually for now.

```js
import got from 'got'

export default async () => {
const topics = await got('https://api.com/all/topics/').json()
return {
generate: {
routes: () => topics.data.map(topic => /themen/${topic.slug}),
fallback: true,
},
pwa: {
workbox: {
// for offline functionality we need to precache every route
offlineAssets: [
'/',
...topics.data.map(topic => /themen/${topic.slug}/), // notice the trailing slash
'/impressum/',
],
offlinePage: '/404.html',
},
},
},
}
```

I've found another workaround for using it with workbox-cli in nuxt generate mode. It works by using cachingExtensions of the module workbox options.

You then have to make sure that you execute workbox injectManifest after nuxt generate, I did this by modifying my generate build script.

package.json

{
  "scripts": {
    "generate": "nuxt generate && workbox injectManifest"
  }
}

nuxt.config.js

import got from 'got'

export default async () => {
 const topics = await got('https://api.com/all/topics/').json()
 return {
   generate: {
     routes: () => topics.data.map(topic => `/themen/${topic.slug}`),
     fallback: true,
   },
   pwa: {
     workbox: {
       cachingExtensions: 'workbox-caching-extensions.js',
       offlinePage: '/404.html',
     },
   },
 },
}

workbox-caching-extensions.js

workbox.precaching.precacheAndRoute(self.__WB_MANIFEST)

workbox-config.js

module.exports = {
  globDirectory: 'dist/',
  globPatterns: ['**/*.{js,png,json,html}'],
  globIgnores: ['**/*404.html'],
  swSrc: 'dist/sw.js',
  swDest: 'dist/sw.js',
}

Is there any way at all to precache the entire app on the first visit? Our current app relies on this and we are wanting to port to Nuxt but without support for this, we can't.

Is there any way at all to precache the entire app on the first visit? Our current app relies on this and we are wanting to port to Nuxt but without support for this, we can't.

Although this module doesn't support precache yet, it can be done easily enough with workbox.

I've created an example here => https://github.com/matthewblewitt/pwa-workbox-precache-nuxt
Not the cleanest solution as it has to be build twice, but it does the job

I figured out how to precache Nuxt assets by extending @nuxtjs/pwa module with a custom module:

  • First create the custom module in modules/pwa-extension.js:
const { getManifest } = require('workbox-build')

export default function nuxtWorkboxExtension() {
  this.nuxt.hook('build:before', async (nuxt, buildOptions) => {
    const { manifestEntries } = await getManifest({
      globDirectory: this.options.srcDir + '/.nuxt/dist/client',
      globPatterns: [
        '**/*.{js,css}'
      ],
      modifyURLPrefix: {
        '': '/_nuxt/'
      },
    })
    const preCaching = nuxt.options.pwa.workbox.preCaching || []
    nuxt.options.pwa.workbox.preCaching = preCaching.concat(manifestEntries)
  })
}
  • Then install the new dependencies:
    npm install --save-dev workbox-build

  • And in nuxt.config.js add '~/modules/pwa-extension.js', BEFORE @nuxtjs/pwa module:

...
  buildModules: [
   ++ '~/modules/pwa-extension.js',
    '@nuxtjs/pwa',
  ],

...

Hope it helps someone!

Here is the output:
dist/sw.js

...

// Precache assets
workbox.precaching.precacheAndRoute([
  {
    "url": "/_nuxt/095913b481da06598c10.js",
    "revision": "7c531fc5d335fccb3d6a24c35c8594a2"
  },
  {
    "url": "/_nuxt/166a293e1d6ad5d866fd.js",
    "revision": "80dd5b58406aad1506bb1f558dd6ae87"
  },
  {
    "url": "/_nuxt/2d693856400d1816dd8b.js",
    "revision": "6a0359d61415a9b1c11932681de2fc6e"
  },
  {
    "url": "/_nuxt/439a0c5fdf0b79da7ca2.js",
    "revision": "848154e004e42c75afeffeecaf230b34"
  },
  {
    "url": "/_nuxt/4a3e62ab662493cb5cfc.js",
    "revision": "319942625297ce9bdfa28c969db7ea5b"
  },
  {
    "url": "/_nuxt/4af9a6acf753d4c6a396.js",
    "revision": "cf952223bc37c9022c52f38fac9451e3"
  },
  {
    "url": "/_nuxt/4da21b79b080a78bc54b.js",
    "revision": "1d3f4547587ec343bf39bb86d5d333e8"
  },
  {
    "url": "/_nuxt/516f114e4dc410626cd3.js",
    "revision": "d7ebb5eec6fee94618687f6a0464fa0e"
  },
  {
    "url": "/_nuxt/71186f87d37673506607.js",
    "revision": "4ca23c785694c500dc83c6096ab0b307"
  },
  {
    "url": "/_nuxt/73a141d2b7aa5186380d.js",
    "revision": "f785dde281fe78cdf4dfe637789c6bd4"
  },
  {
    "url": "/_nuxt/8185600dbb5fd4ad0b52.js",
    "revision": "fa85839594fc546c3207d803b4fdeafe"
  },
  {
    "url": "/_nuxt/8430165e2d73946f43ad.js",
    "revision": "cfa58ce18400a0b2d6b58b5c42f101df"
  },
  {
    "url": "/_nuxt/8c63421d172294efb676.js",
    "revision": "9a65c0f58614014319e698bb2445daa3"
  },
  {
    "url": "/_nuxt/8e6c194253761fce6944.js",
    "revision": "69a17b5109201da6bec8b3a92c1a956b"
  },
  {
    "url": "/_nuxt/95f7180c8a8342c94558.js",
    "revision": "3488f9f2fc98490314e1da635d182cb7"
  },
  {
    "url": "/_nuxt/98b96f20c36b1fad5cdd.js",
    "revision": "6cf6263f0a633c84c7954b2d336dbf83"
  },
  {
    "url": "/_nuxt/9fb84702d874e38b26ab.js",
    "revision": "6ad7488d6935b8e7e95a5c8a4a13fd0c"
  },
  {
    "url": "/_nuxt/a36793ef6b91e9a70082.js",
    "revision": "ee4a118da952237ccb6db42730596cb8"
  },
  {
    "url": "/_nuxt/a424b8d54aff681294a2.js",
    "revision": "0aa09c1a591c705ed88fb8da9aef20fd"
  },
  {
    "url": "/_nuxt/a9dba6f68950a2b9b665.js",
    "revision": "76783fdd4e0aa9609d04fb7c2bb51608"
  },
  {
    "url": "/_nuxt/a9f0459cc46984b436b2.js",
    "revision": "b995683b8d699445691fbaae9ec21a8a"
  },
  {
    "url": "/_nuxt/b12cd7522487fdeba709.js",
    "revision": "a7e29176547a2d3259a2d591080394ad"
  },
  {
    "url": "/_nuxt/b6f9b4b46f00cee7d6ac.js",
    "revision": "91c4737f6a6a1f0cce379602b98a9230"
  },
  {
    "url": "/_nuxt/c4464b595fd7931f989c.js",
    "revision": "3acdbe6ea09d88952b5342a0bf3f22ec"
  },
], {
  "cacheId": "MyApp-prod",
  "directoryIndex": "/"
})
...

@andresdameson Thanks for that, it works! Is there anyway this would work in universal mode or is this only possible in SPA mode?

@andresdameson Thanks for that, it works! Is there anyway this would work in universal mode or is this only possible in SPA mode?

I guess you should change "/client" to "/server" in globDirectory option when not in client side, but I'm not certain.

Also, I notice that it seems to build it on the _previous build_ .nuxt/dist/client - is there any way to do this on the current build?

Also, I notice that it seems to build it on the _previous build_ .nuxt/dist/client - is there any way to do this on the current build?

You are right! I adjusted the module:

  • First create the custom module in modules/pwa-extension.js:
const path = require('path')
const { injectManifest } = require('workbox-build')

export default function nuxtWorkboxExtension() {
  this.nuxt.hook('build:before', async (nuxt) => {
    let cachingExtensions = nuxt.options.pwa.workbox.cachingExtensions || []
    cachingExtensions = Array.isArray(cachingExtensions) ? cachingExtensions : [cachingExtensions]
    nuxt.options.pwa.workbox.cachingExtensions = cachingExtensions.concat(['~/modules/pwa-extension-inject.js'])
  })
  this.nuxt.hook('build:compiled', async () => {
    const swFile = path.resolve(this.options.srcDir, this.options.dir.static || 'static', 'sw.js')
    await injectManifest({
      globDirectory: this.options.srcDir + '/dist/',
      globPatterns: [
        '**/*.{js,css}'
      ],
      swSrc: swFile,
      swDest: swFile,
      injectionPoint: 'self.__PWA_EXTENSION'
    })
  })
}
  • Then create a new file in ~/modules/ called pwa-extension-inject.js:
workbox.precaching.precacheAndRoute(self.__PWA_EXTENSION)
  • And then install the new dependencies:
    npm install --save-dev workbox-build

  • And in nuxt.config.js add '~/modules/pwa-extension.js', BEFORE @nuxtjs/pwa module:

...
  buildModules: [
   ++ '~/modules/pwa-extension.js',
    '@nuxtjs/pwa',
  ],
...

Maybe this also solves the problem with universal mode.

Not sure if I am testing this correctly but I basically delete the .nuxt folder and dist folder then run nuxt build - doing this still shows up empty for me.

Edit:

Changing globDirectory to this.options.srcDir + '/.nuxt/dist/client' and adding modifyURLPrefix back seems to work with this? Still no luck with universal mode however

How about changing globDirectory to this.options.srcDir + '/.nuxt/dist/', and setting modifyURLPrefix to this?:

modifyURLPrefix: {
     'client/': '/_nuxt/',
     'server/': '/_nuxt/'
 },

Maybe reading files from both folders solves de issue with universal mode.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xrei picture xrei  Â·  9Comments

joberthel picture joberthel  Â·  11Comments

Shuunen picture Shuunen  Â·  8Comments

lihbr picture lihbr  Â·  4Comments

homerjam picture homerjam  Â·  3Comments