nuxt-community / pwa-module

Zero config PWA solution for Nuxt.js
https://pwa.nuxtjs.org
MIT License
1.24k stars 171 forks source link

Compatibility with Workbox Webpack InjectManifest Plugin #178

Open raayu83 opened 5 years ago

raayu83 commented 5 years ago

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)
pi0 commented 5 years ago

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.

raayu83 commented 5 years ago

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.

pi0 commented 5 years ago

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 :)

salmasov commented 5 years ago

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

larsvankleef commented 4 years ago

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?

RobinMarsden-NHM commented 4 years ago

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!

matthewblewitt commented 4 years ago

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

studnitz commented 4 years ago

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.

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',
      },
    },
  },
}
studnitz commented 4 years ago

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',
}
kierendev commented 4 years ago

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.

matthewblewitt commented 4 years ago

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

andresdameson commented 4 years ago

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

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": "/" }) ...

kierendev commented 4 years ago

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

andresdameson commented 4 years ago

@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.

kierendev commented 4 years ago

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?

andresdameson commented 4 years ago

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:

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.
kierendev commented 4 years ago

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

andresdameson commented 4 years ago

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.