shadowwalker / next-pwa

Zero config PWA plugin for Next.js, with workbox 🧰
MIT License
3.75k stars 311 forks source link

service worker doesn't work in project with basePath when routing from start_url through next/link #400

Open huaxiaocheng opened 1 year ago

huaxiaocheng commented 1 year ago

Summary

I have basePath in my project, the solution I see so far is to add trailingSlash: true to make the service worker work at start_url, so the first question is, is there any other solution? trailingSlash: true affects my project too much, I can't do it for now.

The second problem is that I don't add trailingSlash: true and I also accept that start_url doesn't work. Now visiting start_url, I can listen to the response of the installed and activated events of the service worker, but not the controlling event, so there is no reload(), and then I route through next/link , which apparently also doesn't havereload()`, so the service worker doesn't work.

Also, after visiting another page and refreshing, the service worker works, cacheOnFrontEndNav: true makes the cache available. When I close the browser, reopen and visit start_url, the status of the service worker is stopped, because start_url is not in scope, which is understandable. But I route through next/link and the service worker does not become running to use the cache.

I might be able to solve the second problem above by performing a reload() by listening if the route is coming from start_url.

But I want to know if there are currently configuration items or other solutions to solve this problem, I don't think this is a very strange requirement, another requirement scenario can also reproduce this problem, that is "there is no basePath , but scope does not contain start_url, then routes from start_url through next/link"

Versions

How To Reproduce

next.config.js

const withPWA = require('next-pwa')({
  dest: 'public',
  register: false,
  cacheOnFrontEndNav: true,
  cacheStartUrl: false,
  dynamicStartUrl: false
})

module.exports = withPWA({
  basePath: '/hello'
})

_app.js


const _App = ({ Component, pageProps }) => {
    // This hook only run once in browser after the component is rendered for the first time.
    // It has same effect as the old componentDidMount lifecycle callback.
    useEffect(() => {
        if (typeof window !== 'undefined' && 'serviceWorker' in navigator && window.workbox !== undefined) {
            const wb = window.workbox
            // add event listeners to handle any of PWA lifecycle event
            // https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-window.Workbox#events
            wb.addEventListener('installed', event => {
                console.log(`Event ${event.type} is triggered.`)
                console.log(event)
            })

            wb.addEventListener('controlling', event => {
                console.log(`Event ${event.type} is triggered.`)
                console.log(event)
                // window.location.reload()
            })

            wb.addEventListener('activated', event => {
                console.log(`Event ${event.type} is triggered.`)
                console.log(event)
            })

            // ISSUE - this is not working as expected, why?
            // I could only make message event listenser work when I manually add this listenser into sw.js file
            wb.addEventListener('message', event => {
                console.log(`Event ${event.type} is triggered.`)
                console.log(event)
            })

            wb.addEventListener('redundant', event => {
                console.log(`Event ${event.type} is triggered.`)
                console.log(event)
            })

            wb.addEventListener('externalinstalled', event => {
                console.log(`Event ${event.type} is triggered.`)
                console.log(event)
            })

            wb.addEventListener('externalactivated', event => {
                console.log(`Event ${event.type} is triggered.`)
                console.log(event)
            })

            // never forget to call register as auto register is turned off in next.config.js
            wb.register()
        }
    }, [])

    return <Component {...pageProps} />
}

export default _App
SergeySych commented 1 year ago

Try to use this https://github.com/shadowwalker/next-pwa/issues/278#issuecomment-1476641350