Skip to content

Commit 82e9e68

Browse files
committed
fix(@angular/build): only generate shallow preload links for initial files
To remove the potential for a large amount of modulepreload link elements being added to the generating `index.html` for an application, the number of elements is now limited to three. Also, only first-level initial scripts will be added. Previously all initial scripts regardless of depth were eligible for preloading. The preload generation can still be fully disabled via the `index.preloadInitial` option within the build options.
1 parent 0fe5066 commit 82e9e68

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

packages/angular/build/src/tools/esbuild/bundler-context.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export interface InitialFileRecord {
4343
type: 'script' | 'style';
4444
external?: boolean;
4545
serverFile: boolean;
46+
depth: number;
4647
}
4748

4849
export enum BuildOutputFileType {
@@ -298,6 +299,7 @@ export class BundlerContext {
298299
type,
299300
entrypoint: true,
300301
serverFile: this.#platformIsServer,
302+
depth: 0,
301303
};
302304

303305
if (!this.initialFilter || this.initialFilter(record)) {
@@ -308,10 +310,19 @@ export class BundlerContext {
308310
}
309311

310312
// Analyze for transitive initial files
311-
const files = [...initialFiles.keys()];
312-
for (const file of files) {
313-
for (const initialImport of result.metafile.outputs[file].imports) {
314-
if (initialFiles.has(initialImport.path)) {
313+
const entriesToAnalyze = [...initialFiles];
314+
let currentEntry;
315+
while ((currentEntry = entriesToAnalyze.pop())) {
316+
const [entryPath, entryRecord] = currentEntry;
317+
318+
for (const initialImport of result.metafile.outputs[entryPath].imports) {
319+
const existingRecord = initialFiles.get(initialImport.path);
320+
if (existingRecord) {
321+
// Store the smallest value depth
322+
if (existingRecord.depth > entryRecord.depth + 1) {
323+
existingRecord.depth = entryRecord.depth + 1;
324+
}
325+
315326
continue;
316327
}
317328

@@ -321,14 +332,15 @@ export class BundlerContext {
321332
entrypoint: false,
322333
external: initialImport.external,
323334
serverFile: this.#platformIsServer,
335+
depth: entryRecord.depth + 1,
324336
};
325337

326338
if (!this.initialFilter || this.initialFilter(record)) {
327339
initialFiles.set(initialImport.path, record);
328340
}
329341

330342
if (!initialImport.external) {
331-
files.push(initialImport.path);
343+
entriesToAnalyze.push([initialImport.path, record]);
332344
}
333345
}
334346
}

packages/angular/build/src/tools/esbuild/index-html-generator.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ import { NormalizedApplicationBuildOptions } from '../../builders/application/op
1212
import { IndexHtmlGenerator } from '../../utils/index-file/index-html-generator';
1313
import { BuildOutputFile, BuildOutputFileType, InitialFileRecord } from './bundler-context';
1414

15+
/**
16+
* The maximum number of module preload link elements that should be added for
17+
* initial scripts.
18+
*/
19+
const MODULE_PRELOAD_MAX = 3;
20+
1521
export async function generateIndexHtml(
1622
initialFiles: Map<string, InitialFileRecord>,
1723
outputFiles: BuildOutputFile[],
@@ -39,13 +45,20 @@ export async function generateIndexHtml(
3945
assert(indexHtmlOptions, 'indexHtmlOptions cannot be undefined.');
4046

4147
if (!externalPackages && indexHtmlOptions.preloadInitial) {
48+
let modulePreloadCount = 0;
4249
for (const [key, value] of initialFiles) {
4350
if (value.entrypoint || value.serverFile) {
4451
// Entry points are already referenced in the HTML
4552
continue;
4653
}
4754

48-
if (value.type === 'script') {
55+
// Only add shallow preloads
56+
if (value.depth > 1) {
57+
continue;
58+
}
59+
60+
if (value.type === 'script' && modulePreloadCount < MODULE_PRELOAD_MAX) {
61+
modulePreloadCount++;
4962
hints.push({ url: key, mode: 'modulepreload' as const });
5063
} else if (value.type === 'style') {
5164
// Provide an "as" value of "style" to ensure external URLs which may not have a

0 commit comments

Comments
 (0)