fix(service-worker): improve ServiceWorker cache names (#42622)

This commit improves the cache names generated by the ServiceWorker by
making them shorter and non-repetitive. In particular, the following
changes are made:

- Data-group cache names no longer include the `dynamic` infix, since it
  does not add any value.
  Before: `ngsw:<...>:data:dynamic:<...>`
  After:  `ngsw:<...>:data:<...>`

- `CacheDatabase` table names no longer include the `ngsw:<path>` prefix
  twice.
  Before: `ngsw:<path>:db:ngsw:<path>:<...>`
  After:  `ngsw:<path>:db:<...>`

NOTE 1:
This change will result in different cache names being generated for the
same app-versions with the new SericeWorker script. This means that some
of the previously cached data will need to be re-downloaded (because the
ServiceWorker will not be able to re-use the old caches), but that
should be transparent for the end user.
While possible, adding logic to allow the ServiceWorker to retrieve data
from the old caches is not worth the extra complecity and maintenance
cost.

NOTE 2:
Generating different cache names for some of the caches means that the
ServiceWorker will not be able to clean-up some of the old caches. This
will be taken care of in a subsequent commit that will rework the
clean-up logic to be more robust (covering changes such as this one and
other edgecases).

PR Close #42622
This commit is contained in:
George Kalpakas 2021-06-23 15:27:50 +03:00 committed by Jessica Janiuk
parent 7507ed2e54
commit 73b0275dc2
4 changed files with 23 additions and 21 deletions

View File

@ -77,7 +77,7 @@ export class AppVersion implements UpdateSource {
// Process each `AssetGroup` declared in the manifest. Each declared group gets an `AssetGroup`
// instance created for it, of a type that depends on the configuration mode.
const assetCacheNamePrefix = `${adapter.cacheNamePrefix}:${manifestHash}:assets`;
const assetCacheNamePrefix = `${manifestHash}:assets`;
this.assetGroups = (manifest.assetGroups || []).map(config => {
// Check the caching mode, which determines when resources will be fetched/updated.
switch (config.installMode) {
@ -91,11 +91,11 @@ export class AppVersion implements UpdateSource {
});
// Process each `DataGroup` declared in the manifest.
this.dataGroups = (manifest.dataGroups || [])
.map(
config => new DataGroup(
scope, adapter, config, database, debugHandler,
`${adapter.cacheNamePrefix}:${config.version}:data`));
this.dataGroups =
(manifest.dataGroups || [])
.map(
config => new DataGroup(
scope, adapter, config, database, debugHandler, `${config.version}:data`));
// This keeps backwards compatibility with app versions without navigation urls.
// Fix: https://github.com/angular/angular/issues/27209

View File

@ -67,7 +67,8 @@ export abstract class AssetGroup {
// This is the primary cache, which holds all of the cached requests for this group. If a
// resource isn't in this cache, it hasn't been fetched yet.
this.cache = scope.caches.open(`${cacheNamePrefix}:${config.name}:cache`);
this.cache =
scope.caches.open(`${adapter.cacheNamePrefix}:${cacheNamePrefix}:${config.name}:cache`);
// This is the metadata table, which holds specific information for each cached URL, such as
// the timestamp of when it was added to the cache.
@ -103,7 +104,8 @@ export abstract class AssetGroup {
* Clean up all the cached data for this group.
*/
async cleanup(): Promise<void> {
await this.scope.caches.delete(`${this.cacheNamePrefix}:${this.config.name}:cache`);
await this.scope.caches.delete(
`${this.adapter.cacheNamePrefix}:${this.cacheNamePrefix}:${this.config.name}:cache`);
await this.db.delete(`${this.cacheNamePrefix}:${this.config.name}:meta`);
}

View File

@ -249,11 +249,10 @@ export class DataGroup {
private config: DataGroupConfig, private db: Database, private debugHandler: DebugHandler,
private cacheNamePrefix: string) {
this.patterns = config.patterns.map(pattern => new RegExp(pattern));
this.cache = scope.caches.open(`${cacheNamePrefix}:dynamic:${config.name}:cache`);
this.lruTable =
this.db.open(`${cacheNamePrefix}:dynamic:${config.name}:lru`, config.cacheQueryOptions);
this.ageTable =
this.db.open(`${cacheNamePrefix}:dynamic:${config.name}:age`, config.cacheQueryOptions);
this.cache =
scope.caches.open(`${adapter.cacheNamePrefix}:${cacheNamePrefix}:${config.name}:cache`);
this.lruTable = this.db.open(`${cacheNamePrefix}:${config.name}:lru`, config.cacheQueryOptions);
this.ageTable = this.db.open(`${cacheNamePrefix}:${config.name}:age`, config.cacheQueryOptions);
}
/**
@ -550,9 +549,10 @@ export class DataGroup {
async cleanup(): Promise<void> {
// Remove both the cache and the database entries which track LRU stats.
await Promise.all([
this.scope.caches.delete(`${this.cacheNamePrefix}:dynamic:${this.config.name}:cache`),
this.db.delete(`${this.cacheNamePrefix}:dynamic:${this.config.name}:age`),
this.db.delete(`${this.cacheNamePrefix}:dynamic:${this.config.name}:lru`),
this.scope.caches.delete(
`${this.adapter.cacheNamePrefix}:${this.cacheNamePrefix}:${this.config.name}:cache`),
this.db.delete(`${this.cacheNamePrefix}:${this.config.name}:age`),
this.db.delete(`${this.cacheNamePrefix}:${this.config.name}:lru`),
]);
}

View File

@ -1269,12 +1269,12 @@ describe('Driver', () => {
const cacheKeysFor = (baseHref: string, manifestHash: string) =>
[`ngsw:${baseHref}:db:control`,
`ngsw:${baseHref}:${manifestHash}:assets:eager:cache`,
`ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:eager:meta`,
`ngsw:${baseHref}:db:${manifestHash}:assets:eager:meta`,
`ngsw:${baseHref}:${manifestHash}:assets:lazy:cache`,
`ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:lazy:meta`,
`ngsw:${baseHref}:42:data:dynamic:api:cache`,
`ngsw:${baseHref}:db:ngsw:${baseHref}:42:data:dynamic:api:lru`,
`ngsw:${baseHref}:db:ngsw:${baseHref}:42:data:dynamic:api:age`,
`ngsw:${baseHref}:db:${manifestHash}:assets:lazy:meta`,
`ngsw:${baseHref}:42:data:api:cache`,
`ngsw:${baseHref}:db:42:data:api:lru`,
`ngsw:${baseHref}:db:42:data:api:age`,
];
const createManifestWithBaseHref = (baseHref: string, distDir: MockFileSystem): Manifest => ({