Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

workbox-build: add option to handle dynamic routes when using generateSW #2917

Closed
userquin opened this issue Aug 14, 2021 · 3 comments
Closed

Comments

@userquin
Copy link

This is not a bug, it is an enhancement for dynamic routes configuration.

Library Affected:
workbox-build: generateSW method

Browser & Platform:
do not apply, it is a node module

Feature Request Description:

When building an SPA, using generateSW from workbox-build module to build the service worker, there will be dynamic routes, for example user/:id: there is no way to configure dynamic navigation on generateSW.

For example, we only can add the SPA fallback, generateSW will generate this:

e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))

It will be very usefull if we can use a new option, or expose registerRoute on configuration to serve the dynamic routes content.

For example, I have a custom service worker using injectManifest to achieve the behavior:

// sw.ts
import { precacheAndRoute, cleanupOutdatedCaches, createHandlerBoundToURL } from 'workbox-precaching'
import { clientsClaim } from 'workbox-core'
import { registerRoute } from 'workbox-routing'

declare let self: ServiceWorkerGlobalScope

self.skipWaiting()
clientsClaim()

// self.__WB_MANIFEST is default injection point
precacheAndRoute(self.__WB_MANIFEST)

cleanupOutdatedCaches()

const userHandler = createHandlerBoundToURL('user/:id')
const indexHandler = createHandlerBoundToURL('index.html')

registerRoute(/./, async(options) => {
  const { url } = options
  if (url.pathname && url.pathname.startsWith('/user/'))
    return await userHandler (options)

  return await indexHandler(options)
}, 'GET')

The main difference is to use a (simple or complex) configuration option entry instead writing a custom service worker, something like using plugins options on runtimeCaching.

You can see an example here: antfu-collective/vitesse#169

@jeffposnick
Copy link
Contributor

It's not obvious from the name, but you can configure the urlPattern in a runtimeCaching entry with any arbitrary JavaScript you want that conforms to the matchCallback interface, and similarly anything for handler that conforms to the handlerCallback interface.

So the following is valid:

{
  runtimeCaching: [{
    urlPattern: ({url}) => url.pathname.startsWith('/user/'),
    handler: () => caches.match('/user.html', {ignoreSearch: true}),
  }],
  // ...other config options...
}

The trickier part about what you're trying to do is that you probably are not going to have access to the createHandlerBoundToURL() from within that configuration code, so you'd need to rely on, e.g., just doing a caches.match() while ignoring the search portion of the URL.

I am not eager to extend generateSW's runtimeCaching significantly at this point, as more complex scenarios are really what injectManifest is intended for. Trying to replicate everything that's possible imperatively via more and more declarative configuration options is ultimately a losing battle. Hopefully that guidance based on the current functionality is sufficient for you.

@userquin
Copy link
Author

@jeffposnick with v6.4.2 using the runtimeCaching approach, the handler is only called with external resources (I'll try with a custom sw):

imagen

@jeffposnick
Copy link
Contributor

I'm not sure if this explains your issue, but using caches.has() in a urlPattern callback is not going to give you the behavior you want, since it returns a Promise, and that will always be evaluated as a truthy value.

We have some development mode logging to catch this if you return a Promise, but because you're using &&, it's going to get translated into a boolean, which won't trigger the logging:

if (process.env.NODE_ENV !== 'production') {
// Warn developers that using an async matchCallback is almost always
// not the right thing to do.
if (matchResult instanceof Promise) {
logger.warn(
`While routing ${getFriendlyURL(url)}, an async ` +
`matchCallback function was used. Please convert the ` +
`following route to use a synchronous matchCallback function:`,
route,
);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants