Skip to content

Commit

Permalink
fix(@angular/build): only generate shallow preload links for initial …
Browse files Browse the repository at this point in the history
…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.

(cherry picked from commit 82e9e68)
  • Loading branch information
clydin committed May 2, 2024
1 parent f683839 commit 2085365
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
22 changes: 17 additions & 5 deletions packages/angular/build/src/tools/esbuild/bundler-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export interface InitialFileRecord {
type: 'script' | 'style';
external?: boolean;
serverFile: boolean;
depth: number;
}

export enum BuildOutputFileType {
Expand Down Expand Up @@ -298,6 +299,7 @@ export class BundlerContext {
type,
entrypoint: true,
serverFile: this.#platformIsServer,
depth: 0,
};

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

// Analyze for transitive initial files
const files = [...initialFiles.keys()];
for (const file of files) {
for (const initialImport of result.metafile.outputs[file].imports) {
if (initialFiles.has(initialImport.path)) {
const entriesToAnalyze = [...initialFiles];
let currentEntry;
while ((currentEntry = entriesToAnalyze.pop())) {
const [entryPath, entryRecord] = currentEntry;

for (const initialImport of result.metafile.outputs[entryPath].imports) {
const existingRecord = initialFiles.get(initialImport.path);
if (existingRecord) {
// Store the smallest value depth
if (existingRecord.depth > entryRecord.depth + 1) {
existingRecord.depth = entryRecord.depth + 1;
}

continue;
}

Expand All @@ -321,14 +332,15 @@ export class BundlerContext {
entrypoint: false,
external: initialImport.external,
serverFile: this.#platformIsServer,
depth: entryRecord.depth + 1,
};

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

if (!initialImport.external) {
files.push(initialImport.path);
entriesToAnalyze.push([initialImport.path, record]);
}
}
}
Expand Down
15 changes: 14 additions & 1 deletion packages/angular/build/src/tools/esbuild/index-html-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import { NormalizedApplicationBuildOptions } from '../../builders/application/op
import { IndexHtmlGenerator } from '../../utils/index-file/index-html-generator';
import { BuildOutputFile, BuildOutputFileType, InitialFileRecord } from './bundler-context';

/**
* The maximum number of module preload link elements that should be added for
* initial scripts.
*/
const MODULE_PRELOAD_MAX = 3;

export async function generateIndexHtml(
initialFiles: Map<string, InitialFileRecord>,
outputFiles: BuildOutputFile[],
Expand Down Expand Up @@ -39,13 +45,20 @@ export async function generateIndexHtml(
assert(indexHtmlOptions, 'indexHtmlOptions cannot be undefined.');

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

if (value.type === 'script') {
// Only add shallow preloads
if (value.depth > 1) {
continue;
}

if (value.type === 'script' && modulePreloadCount < MODULE_PRELOAD_MAX) {
modulePreloadCount++;
hints.push({ url: key, mode: 'modulepreload' as const });
} else if (value.type === 'style') {
// Provide an "as" value of "style" to ensure external URLs which may not have a
Expand Down

0 comments on commit 2085365

Please sign in to comment.