From 8e4bb0e4cd477f42519ebb0fcc9236fd4d90c270 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Fri, 4 Sep 2026 07:19:55 +0000 Subject: [PATCH] fix(@angular/build): default preloadInitial to false when serviceWorker is enabled When a service worker is enabled, application assets are prefetched and served from Cache Storage. Emitting `` hints for initial shared chunks causes Chromium to discard them with a "cross-world service worker resource mismatch" warning on repeat visits, as well as triggering redundant network fetches. This change sets the default of `preloadInitial` to `false` when the `serviceWorker` option is enabled, while still allowing developers to explicitly override it if desired. Fixes #34022 --- .../build/src/builders/application/options.ts | 9 +++-- .../src/builders/application/schema.json | 1 - .../tests/options/service-worker_spec.ts | 36 +++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/angular/build/src/builders/application/options.ts b/packages/angular/build/src/builders/application/options.ts index abe3298aa093..dc53d55b61f0 100644 --- a/packages/angular/build/src/builders/application/options.ts +++ b/packages/angular/build/src/builders/application/options.ts @@ -384,6 +384,8 @@ export async function normalizeOptions( ? INDEX_HTML_CSR : indexBaseName; + const preloadInitialDefault = !options.serviceWorker; + indexHtmlOptions = { input: indexInput, output: indexOutput, @@ -395,8 +397,11 @@ export async function normalizeOptions( // [name, esm] ] as [string, boolean][], transformer: extensions?.indexHtmlTransformer, - // Preload initial defaults to true - preloadInitial: typeof options.index !== 'object' || (options.index.preloadInitial ?? true), + // Preload initial defaults to false when using a service worker, true otherwise + preloadInitial: + typeof options.index === 'object' + ? (options.index?.preloadInitial ?? preloadInitialDefault) + : preloadInitialDefault, }; } diff --git a/packages/angular/build/src/builders/application/schema.json b/packages/angular/build/src/builders/application/schema.json index 8bf30aec8298..4e20cdd0da07 100644 --- a/packages/angular/build/src/builders/application/schema.json +++ b/packages/angular/build/src/builders/application/schema.json @@ -520,7 +520,6 @@ }, "preloadInitial": { "type": "boolean", - "default": true, "description": "Generates 'preload', 'modulepreload', and 'preconnect' link elements for initial application files and resources." } }, diff --git a/packages/angular/build/src/builders/application/tests/options/service-worker_spec.ts b/packages/angular/build/src/builders/application/tests/options/service-worker_spec.ts index 444babc37a02..8711f36211ba 100644 --- a/packages/angular/build/src/builders/application/tests/options/service-worker_spec.ts +++ b/packages/angular/build/src/builders/application/tests/options/service-worker_spec.ts @@ -89,6 +89,42 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { expect(JSON.parse(config)).toEqual(jasmine.objectContaining({ index: '/index.csr.html' })); }); + it('should not generate initial modulepreload hints by default when service worker is enabled', async () => { + // Setup an initial chunk usage for JS + await harness.writeFile('src/a.ts', 'console.log("TEST");'); + await harness.writeFile('src/b.ts', 'import "./a";'); + await harness.writeFile('src/main.ts', 'import "./a";\n(() => import("./b"))();'); + + harness.useTarget('build', { + ...BASE_OPTIONS, + serviceWorker: true, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + harness.expectFile('dist/browser/index.html').content.not.toContain('modulepreload'); + }); + + it('should generate initial modulepreload hints when preloadInitial is explicitly true and service worker is enabled', async () => { + // Setup an initial chunk usage for JS + await harness.writeFile('src/a.ts', 'console.log("TEST");'); + await harness.writeFile('src/b.ts', 'import "./a";'); + await harness.writeFile('src/main.ts', 'import "./a";\n(() => import("./b"))();'); + + harness.useTarget('build', { + ...BASE_OPTIONS, + serviceWorker: true, + index: { + input: 'src/index.html', + preloadInitial: true, + }, + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + harness.expectFile('dist/browser/index.html').content.toContain('modulepreload'); + }); + it('should write JS-imported CSS chunk to browser dist when SSR is enabled', async () => { await harness.modifyFile('src/tsconfig.app.json', (content) => { const tsConfig = JSON.parse(content);