diff --git a/packages/service-worker/worker/src/assets.ts b/packages/service-worker/worker/src/assets.ts index d22969a6ada..54fb4f66dc6 100644 --- a/packages/service-worker/worker/src/assets.ts +++ b/packages/service-worker/worker/src/assets.ts @@ -501,12 +501,16 @@ export abstract class AssetGroup { * Create a new `Request` based on the specified URL and `RequestInit` options, preserving only * metadata that are known to be safe. * - * Currently, headers, redirect policy, and an explicit `credentials: 'omit'` are preserved. + * Currently, headers, redirect policy, an explicit `credentials: 'omit'`, and the HTTP cache + * mode are preserved. * * NOTE: * `credentials: 'same-origin'` and `credentials: 'include'` are intentionally not preserved. * Forwarding `'include'` could leak cookies to cross-origin asset hosts, and forwarding * `'same-origin'` matches the default `fetch()` behavior so there is nothing to preserve. + * Requests with `cache: 'only-if-cached'` and `mode !== 'same-origin'` are short-circuited + * earlier in `Driver.onFetch()` (they are a known Chrome DevTools quirk), so no special + * handling for that combination is needed here. * TODO(gkalpak): * Investigate preserving more metadata. See, also, discussion on preserving `mode`: * https://github.com/angular/angular/issues/41931#issuecomment-1227601347. @@ -521,6 +525,10 @@ export abstract class AssetGroup { init.credentials = 'omit'; } + if (options.cache !== undefined) { + init.cache = options.cache; + } + return this.adapter.newRequest(url, init); } diff --git a/packages/service-worker/worker/test/happy_spec.ts b/packages/service-worker/worker/test/happy_spec.ts index ad3af0a5d6f..09b94ab4349 100644 --- a/packages/service-worker/worker/test/happy_spec.ts +++ b/packages/service-worker/worker/test/happy_spec.ts @@ -1667,6 +1667,18 @@ import {envIsSupported} from '../testing/utils'; expect(bazReq.credentials).toBe('omit'); }); + it(`passes 'cache' through to the server`, async () => { + // Request a lazy-cached asset (so that it is fetched from the network) and provide an + // explicit HTTP cache mode. + const reqInit = {cache: 'no-store'}; + expect(await makeRequest(scope, '/baz.txt', undefined, reqInit)).toBe('this is baz'); + + // Verify that the explicit `cache` value was preserved (instead of being replaced by the + // default `'default'`). + const [bazReq] = server.getRequestsFor('/baz.txt'); + expect(bazReq.cache).toBe('no-store'); + }); + describe('for redirect requests', () => { it('passes headers through to the server', async () => { // Request a redirected, lazy-cached asset (so that it is fetched from the network) and @@ -1721,6 +1733,20 @@ import {envIsSupported} from '../testing/utils'; const [redirectReq] = server.getRequestsFor('/lazy/redirect-target.txt'); expect(redirectReq.credentials).toBe('omit'); }); + + it(`passes 'cache' through to the server`, async () => { + // Request a redirected, lazy-cached asset (so that it is fetched from the network) and + // provide an explicit HTTP cache mode. + const reqInit = {cache: 'no-store'}; + expect(await makeRequest(scope, '/lazy/redirected.txt', undefined, reqInit)).toBe( + 'this was a redirect too', + ); + + // Verify that the explicit `cache` value was preserved across the redirect + // reconstruction (instead of being replaced by the default `'default'`). + const [redirectReq] = server.getRequestsFor('/lazy/redirect-target.txt'); + expect(redirectReq.cache).toBe('no-store'); + }); }); }); diff --git a/packages/service-worker/worker/testing/fetch.ts b/packages/service-worker/worker/testing/fetch.ts index 587cde897c6..1f815436aa1 100644 --- a/packages/service-worker/worker/testing/fetch.ts +++ b/packages/service-worker/worker/testing/fetch.ts @@ -167,6 +167,7 @@ export class MockRequest extends MockBody implements Request { } return new MockRequest(this.url, { body: this._body, + cache: this.cache, mode: this.mode, credentials: this.credentials, headers: this.headers,