-
Notifications
You must be signed in to change notification settings - Fork 832
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
Sw lib caching strategies #108
Changes from 3 commits
7ad1b69
a245226
0f490e1
6b7ea24
9e11ac2
fe2613b
1a75be4
efbf3e8
73bd04f
f1396cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,54 @@ if (!assert.isSWEnv()) { | |
throw ErrorFactory.createError('not-in-sw'); | ||
} | ||
|
||
/** | ||
* The sw-lib module is a high-level library that makes it easier to | ||
* configure routes with caching strategies as well as manage precaching | ||
* of assets during the install step of a service worker. | ||
* | ||
* @example | ||
* importScripts('/<Path to Module>/build/sw-lib.min.js'); | ||
* | ||
* // cacheRevisionedAssets() can take an array of strings with | ||
* // the revision details in the url. | ||
* goog.swlib.cacheRevisionedAssets([ | ||
* '/styles/main.1234.css', | ||
* '/images/logo.abcd.jpg' | ||
* ]); | ||
* | ||
* // Or it can accept objects with the URL and revision data | ||
* // kept seperate. | ||
* goog.swlib.cacheRevisionedAssets([ | ||
* { | ||
* url: '/index.html', | ||
* revision: '1234' | ||
* }, | ||
* { | ||
* url: '/about.html', | ||
* revision: 'abcd' | ||
* } | ||
* ]); | ||
* | ||
* // If you have assets that aren't revisioned, you can cache them | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggested rephrasing:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the moment the precaching module doesn't configure fetch routes, so technically both require "run time caching strategies". |
||
* // during the installation of you service work using warmRuntimeCache() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "service work" ➡️ "service worker" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
* goog.swlib.warmRuntimeCache([ | ||
* '/scripts/main.js', | ||
* '/images/default-avater.png' | ||
* ]); | ||
* | ||
* // warmRuntimeCache can also accept Requests, in case you need greater | ||
* // control over the request. | ||
* goog.swlib.warmRuntimeCache([ | ||
* new Request('/images/logo.png'), | ||
* new Request('/api/data.json') | ||
* ]); | ||
* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
* goog.swlib.router.registerRoute('/', goog.swlib.cacheFirst); | ||
* goog.swlib.router.registerRoute('/example/', goog.swlib.networkFirst); | ||
* | ||
* @module sw-lib | ||
*/ | ||
|
||
const swLibInstance = new SWLib(); | ||
swLibInstance.Route = Route; | ||
export default swLibInstance; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,36 +17,51 @@ | |
|
||
import RouterWrapper from './router-wrapper.js'; | ||
import ErrorFactory from './error-factory.js'; | ||
import {PrecacheManager} | ||
from '../../../sw-precaching/src/index.js'; | ||
import {PrecacheManager} from '../../../sw-precaching/src/index.js'; | ||
import { | ||
CacheFirst, CacheOnly, NetworkFirst, NetworkOnly, StaleWhileRevalidate, | ||
} from '../../../sw-runtime-caching/src/index.js'; | ||
|
||
/** | ||
* This is a high level library to help with using service worker | ||
* precaching and run time caching. | ||
* | ||
* @memberof module:sw-lib | ||
*/ | ||
class SWLib { | ||
/** | ||
* Initialises the classes router wrapper. | ||
* Initialises an instance of SWLib. An instance of this class is | ||
* accessible when the module is imported into a service worker as | ||
* `self.goog.swlib`. | ||
*/ | ||
constructor() { | ||
this._router = new RouterWrapper(); | ||
this._precacheManager = new PrecacheManager(); | ||
this._strategies = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we talked about this last week, I misunderstood and thought that your plan was to export the class definitions—basically, aliasing them under the These strategies are most useful when you have some control over their behavior via the Do you all share those concerns? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes and no. This API matches that of There are three 1 options:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The I guess we could take inspiration from that and allow developers to pass in a For that approach to work, the second parameter should be the an uninstantiated reference to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In toolbox I would always go:
The options generally would be global rather than per route. Would it be worth me removing the strategies from this PR, landing the doc changes and then discussing the strategies in an issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, yanking them out of this PR and discussing the approach off-thread would make sense. There are lots of common use cases for per-route configs that we'd need to support, like one route that used a dedicated |
||
cacheFirst: new CacheFirst(), | ||
cacheOnly: new CacheOnly(), | ||
networkFirst: new NetworkFirst(), | ||
networkOnly: new NetworkOnly(), | ||
fastest: new StaleWhileRevalidate(), | ||
}; | ||
} | ||
|
||
/** | ||
* Can be used to define debug logging, default cache name etc. | ||
* @param {Object} options The options to set. | ||
*/ | ||
setOptions(options) { | ||
|
||
} | ||
|
||
/** | ||
* If there are assets that are revisioned, they can be cached intelligently | ||
* Revisioned assets can be cached intelligently | ||
* during the install (i.e. old files are cleared from the cache, new files | ||
* are added tot he cache and unchanged files are left as is). | ||
* @param {Array<String>} revisionedFiles A set of urls to cache when the | ||
* service worker is installed. | ||
* are added to the cache and unchanged files are left as is). | ||
* | ||
* @example | ||
* self.goog.swlib.cacheRevisionedAssets([ | ||
* '/styles/main.1234.css', | ||
* { | ||
* url: '/index.html', | ||
* revision: '1234' | ||
* } | ||
* ]); | ||
* | ||
* @param {Array<String|Object>} revisionedFiles A set of urls to cache | ||
* when the service worker is installed. | ||
*/ | ||
cacheRevisionedAssets(revisionedFiles) { | ||
// Add a more helpful error message than assertion error. | ||
|
@@ -60,10 +75,18 @@ class SWLib { | |
} | ||
|
||
/** | ||
* If there are assets that should be cached on the install step but | ||
* aren't revisioned, you can cache them here. | ||
* @param {Array<String>} unrevisionedFiles A set of urls to cache when the | ||
* service worker is installed. | ||
* Any assets you wish to cache which can't be revisioned should be | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about:
Since in many of the cases for unversioned resources, just populating the caches via a runtime caching strategy is desirable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
* cached with this method. All assets are cached on install regardless of | ||
* whether an older version of the request is in the cache. | ||
* | ||
* @example | ||
* self.goog.swlib.warmRuntimeCache([ | ||
* '/scripts/main.js', | ||
* new Request('/images/logo.png') | ||
* ]); | ||
* | ||
* @param {Array<String|Request>} unrevisionedFiles A set of urls to cache | ||
* when the service worker is installed. | ||
*/ | ||
warmRuntimeCache(unrevisionedFiles) { | ||
// Add a more helpful error message than assertion error. | ||
|
@@ -77,12 +100,81 @@ class SWLib { | |
} | ||
|
||
/** | ||
* A getter for the Router Wrapper. | ||
* @return {RouterWrapper} Returns the Router Wrapper | ||
* You can access the [Router]{@link module:sw-lib.RouterWrapper} | ||
* with `self.goog.swlib.router`. | ||
* @return {RouterWrapper} Returns the Router. | ||
*/ | ||
get router() { | ||
return this._router; | ||
} | ||
|
||
/** | ||
* This handler will check is there is a cache response and respond with it if | ||
* there is, otherwise it will make a network request and respond with that, | ||
* caching the response for the next time it's requested. | ||
* | ||
* @example | ||
* self.goog.swlib.router.registerRoute('/', self.google.swlib.cacheFirst); | ||
* | ||
* @return {Handler} A CacheFirst response handler. | ||
*/ | ||
get cacheFirst() { | ||
return this._strategies.cacheFirst; | ||
} | ||
|
||
/** | ||
* This handler will check is there is a cache response and respond with it if | ||
* there is, otherwise it will throw an error. | ||
* | ||
* @example | ||
* self.goog.swlib.router.registerRoute('/', self.google.swlib.cacheOnly); | ||
* | ||
* @return {Handler} A CacheOnly response handler. | ||
*/ | ||
get cacheOnly() { | ||
return this._strategies.cacheOnly; | ||
} | ||
|
||
/** | ||
* This handler will attempt to get a response from the network and respond | ||
* with it if available, updating the cache as well. If the network request | ||
* fails, it will respond with any cached response available. | ||
* | ||
* @example | ||
* self.goog.swlib.router.registerRoute('/', self.google.swlib.networkFirst); | ||
* | ||
* @return {Handler} A NetworkFirst response handler. | ||
*/ | ||
get networkFirst() { | ||
return this._strategies.networkFirst; | ||
} | ||
|
||
/** | ||
* This handle will only return with network requests. | ||
* | ||
* @example | ||
* self.goog.swlib.router.registerRoute('/', self.google.swlib.networkOnly); | ||
* | ||
* @return {Handler} A NetworkOnly response handler. | ||
*/ | ||
get networkOnly() { | ||
return this._strategies.networkOnly; | ||
} | ||
|
||
/** | ||
* This handler will check the cache and make a network request for all | ||
* requests. If the caches has a value it will be returned and when the | ||
* network request has finished, the cache will be updated. If there is no | ||
* cached response, the request will be forfilled by the network request. | ||
* | ||
* @example | ||
* self.goog.swlib.router.registerRoute('/', self.google.swlib.fastest); | ||
* | ||
* @return {Handler} A StaleWhileRevalidate response handler. | ||
*/ | ||
get fastest() { | ||
return this._strategies.fastest; | ||
} | ||
} | ||
|
||
export default SWLib; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
importScripts('/node_modules/mocha/mocha.js'); | ||
importScripts('/node_modules/chai/chai.js'); | ||
importScripts('/node_modules/sw-testing-helpers/build/browser/mocha-utils.js'); | ||
|
||
importScripts('/packages/sw-lib/build/sw-lib.min.js'); | ||
|
||
/* global goog */ | ||
|
||
const expect = self.chai.expect; | ||
self.chai.should(); | ||
mocha.setup({ | ||
ui: 'bdd', | ||
reporter: null, | ||
}); | ||
|
||
describe('Test swlib.cacheOnly', function() { | ||
it('should be accessible goog.swlib.cacheOnly', function() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We talked about why these functions aren't just using arrow syntax offline. I think your reason about Mocha breaking decorated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm probably going to stick with the function name for now. Ideally Mocha would change to have a more explicit approach of declaring the timeout and retries of a unit test. |
||
expect(goog.swlib.cacheOnly).to.exist; | ||
}); | ||
}); | ||
|
||
describe('Test swlib.cacheFirst', function() { | ||
it('should be accessible goog.swlib.cacheFirst', function() { | ||
expect(goog.swlib.cacheFirst).to.exist; | ||
}); | ||
}); | ||
|
||
describe('Test swlib.networkOnly', function() { | ||
it('should be accessible goog.swlib.networkOnly', function() { | ||
expect(goog.swlib.networkOnly).to.exist; | ||
}); | ||
}); | ||
|
||
describe('Test swlib.networkFirst', function() { | ||
it('should be accessible goog.swlib.networkFirst', function() { | ||
expect(goog.swlib.networkFirst).to.exist; | ||
}); | ||
}); | ||
|
||
describe('Test swlib.fastest', function() { | ||
it('should be accessible goog.swlib.fastest', function() { | ||
expect(goog.swlib.fastest).to.exist; | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you're trying to show here is that
cacheRevisionedAssets
accepts both filename paths with revisions in there or an object with the raw path and a separate revision number. Is that the case?It might be worth splitting these into two examples (one showing caching a few files with one approach (e.g `/styles/main.1234.css', '/js/main.1234.js' etc) and then the object variation. Might make it more easy to read through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.