Skip to content

Commit 8e4bb0e

Browse files
committed
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 `<link rel="modulepreload">` 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
1 parent 23e3d44 commit 8e4bb0e

3 files changed

Lines changed: 43 additions & 3 deletions

File tree

packages/angular/build/src/builders/application/options.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ export async function normalizeOptions(
384384
? INDEX_HTML_CSR
385385
: indexBaseName;
386386

387+
const preloadInitialDefault = !options.serviceWorker;
388+
387389
indexHtmlOptions = {
388390
input: indexInput,
389391
output: indexOutput,
@@ -395,8 +397,11 @@ export async function normalizeOptions(
395397
// [name, esm]
396398
] as [string, boolean][],
397399
transformer: extensions?.indexHtmlTransformer,
398-
// Preload initial defaults to true
399-
preloadInitial: typeof options.index !== 'object' || (options.index.preloadInitial ?? true),
400+
// Preload initial defaults to false when using a service worker, true otherwise
401+
preloadInitial:
402+
typeof options.index === 'object'
403+
? (options.index?.preloadInitial ?? preloadInitialDefault)
404+
: preloadInitialDefault,
400405
};
401406
}
402407

packages/angular/build/src/builders/application/schema.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,6 @@
520520
},
521521
"preloadInitial": {
522522
"type": "boolean",
523-
"default": true,
524523
"description": "Generates 'preload', 'modulepreload', and 'preconnect' link elements for initial application files and resources."
525524
}
526525
},

packages/angular/build/src/builders/application/tests/options/service-worker_spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,42 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
8989
expect(JSON.parse(config)).toEqual(jasmine.objectContaining({ index: '/index.csr.html' }));
9090
});
9191

92+
it('should not generate initial modulepreload hints by default when service worker is enabled', async () => {
93+
// Setup an initial chunk usage for JS
94+
await harness.writeFile('src/a.ts', 'console.log("TEST");');
95+
await harness.writeFile('src/b.ts', 'import "./a";');
96+
await harness.writeFile('src/main.ts', 'import "./a";\n(() => import("./b"))();');
97+
98+
harness.useTarget('build', {
99+
...BASE_OPTIONS,
100+
serviceWorker: true,
101+
});
102+
103+
const { result } = await harness.executeOnce();
104+
expect(result?.success).toBeTrue();
105+
harness.expectFile('dist/browser/index.html').content.not.toContain('modulepreload');
106+
});
107+
108+
it('should generate initial modulepreload hints when preloadInitial is explicitly true and service worker is enabled', async () => {
109+
// Setup an initial chunk usage for JS
110+
await harness.writeFile('src/a.ts', 'console.log("TEST");');
111+
await harness.writeFile('src/b.ts', 'import "./a";');
112+
await harness.writeFile('src/main.ts', 'import "./a";\n(() => import("./b"))();');
113+
114+
harness.useTarget('build', {
115+
...BASE_OPTIONS,
116+
serviceWorker: true,
117+
index: {
118+
input: 'src/index.html',
119+
preloadInitial: true,
120+
},
121+
});
122+
123+
const { result } = await harness.executeOnce();
124+
expect(result?.success).toBeTrue();
125+
harness.expectFile('dist/browser/index.html').content.toContain('modulepreload');
126+
});
127+
92128
it('should write JS-imported CSS chunk to browser dist when SSR is enabled', async () => {
93129
await harness.modifyFile('src/tsconfig.app.json', (content) => {
94130
const tsConfig = JSON.parse(content);

0 commit comments

Comments
 (0)