Skip to content

Commit 4907d0d

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 4907d0d

3 files changed

Lines changed: 41 additions & 3 deletions

File tree

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,11 @@ export async function normalizeOptions(
395395
// [name, esm]
396396
] as [string, boolean][],
397397
transformer: extensions?.indexHtmlTransformer,
398-
// Preload initial defaults to true
399-
preloadInitial: typeof options.index !== 'object' || (options.index.preloadInitial ?? true),
398+
// Preload initial defaults to false when using a service worker, true otherwise
399+
preloadInitial:
400+
typeof options.index === 'object' && options.index.preloadInitial !== undefined
401+
? options.index.preloadInitial
402+
: !options.serviceWorker,
400403
};
401404
}
402405

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)