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

Support for setting fetchOptions in workbox-precaching #1760

Closed
divyeshsachan opened this issue Nov 15, 2018 · 10 comments
Closed

Support for setting fetchOptions in workbox-precaching #1760

divyeshsachan opened this issue Nov 15, 2018 · 10 comments

Comments

@divyeshsachan
Copy link

Library Affected:
workbox-precaching.dev.js, workbox-precaching.prod.js.

Browser & Platform:
All browser

Issue or Feature Request Description:
Provide an option to explicitly pass fetchOptions while adding precache route .

Provide an option to pass fetchOptions while adding precache route either via workbox.precaching.PrecacheController, workbox.precaching.precacheAndRoute or workbox.precaching.addRoute

This is helpful in applications where custom response is served to user based on browser compatibility or user state. This could be easily achieved in custom request handler but for precaching no option is there.

By looking at source, it is observed that workbox precaching in background uses fetch calls for each asset or page listed to be precached.

_cacheEntryInTemp in class PrecacheController (file PrecacheController.mjs) Line is referenced

fetchOptions is hardcoded as null.

I couldn't find any way to override method _cacheEntryInTemp in PrecacheController class, so to append custom header on precache fetch calls, As the temporary workaround, I've copied entire workbox and started serving it from my server by modifying _cacheEntryInTemp in PrecacheController as below:

_cacheEntryInTemp({ precacheEntry, event, plugins }) {
  var _this3 = this;

  return babelHelpers.asyncToGenerator(function* () {
	var myHeader = new Headers(precacheEntry._networkRequest.headers);
	myHeader.append(myHeaderK, myHeaderV);
    let response = yield fetchWrapper_mjs.fetchWrapper.fetch({
      request: precacheEntry._networkRequest,
      event,
      fetchOptions: {
			  credentials: 'include',
			  headers: myHeader,
			},
      plugins
    });

    if (response.redirected) {
      response = yield cleanRedirect(response);
    }

    yield cacheWrapper_mjs.cacheWrapper.put({
      cacheName: _this3._getTempCacheName(),
      request: precacheEntry._cacheRequest,
      response,
      event,
      plugins
    });

    yield _this3._precacheDetailsModel._addEntry(precacheEntry);

    return true;
  })();
}

before initializing workbox i set myHeaderK (key), myHeaderV (value) for the application based on user browser and other parameters. This is just an example on how this could be beneficial for applications requiring explicit control over dynamic serving of precache pages based on custom parameters.

Therefore, please check if fetchOptions could be added as args in precache in next release.

@jeffposnick
Copy link
Contributor

Sure, we should be able to do that.

It's a little awkward, but the model to follow is the workbox.precaching.addPlugins() method, which is used to set the plugins that end up being used in the precaching fetch() calls:

/**
* Add plugins to precaching.
*
* @param {Array<Object>} newPlugins
*
* @alias workbox.precaching.addPlugins
*/
moduleExports.addPlugins = (newPlugins) => {
plugins = plugins.concat(newPlugins);
};

We could implement workbox.precaching.setFetchOptions() in a similar manner.

@jeffposnick jeffposnick changed the title Please add fetchOptions argument for precache Support for setting fetchOptions in workbox-precaching Nov 19, 2018
@divyeshsachan
Copy link
Author

@jeffposnick Thanks for considering my request. Adding this feature will help users whose application requires additional headers or data in every fetch call including fetch calls of precache. While this could easily be achieved in custom workbox strategies handler, as of now its not seems possible in precache's fetch calls.
Please update this thread after releasing workbox's new version with this feature.
Thanks again.

@ccapndave
Copy link

I would also find this very useful :)

@philipwalton
Copy link
Member

Related to #1857.

FWIW, if you're wanting to do anything custom with precaching, I'd recommend using an instance of PrecacheController rather than the utility precacheAndRoute method (since PrecacheController is much more flexible.

Here's a simple example that shows how to use PrecacheController combined with workbox-routing and workbox-strategy methods for more flexibility:

const PRECACHE_NAME = 'my-precache-name';
const PRECACHE_MANIFEST = [...]; // Inject via workbox-build (or your bundler).

const pc = new workbox.precaching.PrecacheController(PRECACHE_NAME);
pc.addToCacheList(PRECACHE_MANIFEST);

workbox.routing.registerRoute(
  // Use whatever matching callback you need.
  ({url}) => PRECACHE_MANIFEST.includes(url),
  workbox.strategies.cacheFirst({
    cacheName: PRECACHE_NAME,
    plugins: [
      // Add fetch options here...
    ],
  })
);

@ccapndave
Copy link

AFAIK its not possible to set the headers, even when using PrecacheController, although if there is a way I would be happy to hear it :)

@philipwalton
Copy link
Member

AFAIK its not possible to set the headers, even when using PrecacheController, although if there is a way I would be happy to hear it :)

This should be possible by adding plugins (which you can do with both PrecacheController and the utility addPlugins() method), and writing a requestWillFetch method on the plugin.

@ccapndave
Copy link

Ok, great! I'll give that a go. Thanks!

@kashmiry
Copy link

kashmiry commented Feb 6, 2019

I went through the same issue, I am using workbox 3.6.3 and wanted to set custom header for my precacher, I am glad I was able to figure it out, with the help of this issue and digging through the docs.
Here's the code:

// Precache items
const precacheManifest = [/*** YOUR MANIFEST ***/];

// Custom plugin to alter the fetch
const fetchCustomHeader = {
	requestWillFetch: async ({request}) => {
		// Check if it's from your domain
		if(/^.*\:\/\/(?:yourdomain\.test|yourdomain\.com)\/.*/.test(request.url)){
			var myHeader = new Headers(request.headers);
			myHeader.append('TITLE', 'VALUE');
		}
		var customHeader = myHeader;
		
		// Return the new request
		return new Request(request.url, {headers: customHeader});
	}
};

// Precache Controller
const precacheController = new workbox.precaching.PrecacheController(precacheName);
precacheController.addToCacheList(precacheManifest);

/**
 * Install [Event]
 */
self.addEventListener('install', (event) => {
	console.log('install event.');
	// Install precacher
	event.waitUntil(precacheController.install({plugins: [fetchCustomHeader]}));
});

/**
 * Activate [Event]
 */
self.addEventListener('activate', (event) => {
	console.log('activate event.');
	// Activate precacher
	event.waitUntil(precacheController.activate());	
});

In the fetch event I also check against precache, with precacheController.getCachedUrls();
to only serve offline fallback page to requests that are not present in the precache. That's It!

Helpful Resources:

@advaittrivedi
Copy link

I'd also like to know how fetchOptions for workbox-precaching can be made available to workbox-webpack-plugin so it can be configured in webpack.config.js

@jeffposnick
Copy link
Contributor

@advaittrivedi, I don't think that level of customization is going to be possible via GenerateSW plugin usage.

Instead, if you need to customize the fetchOptions in v6, now that #2459 is implemented, using InjectManifest and writing custom service worker code that called the underlying workbox-precaching methods directly would be the way forward.

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

6 participants