From 8f25d4a0331908d1b47da38b1359dc8b3760ec42 Mon Sep 17 00:00:00 2001
From: Alan Agius <17563226+alan-agius4@users.noreply.github.com>
Date: Wed, 16 Apr 2025 07:26:34 +0000
Subject: [PATCH] fix(common): issue a warning instead of an error when
`NgOptimizedImage` exceeds the preload limit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This should not be treated as a hard error, as it doesn’t break the application but merely degrades performance.
Closes #60871
---
.../preload-link-creator.ts | 27 ++++++++-------
.../directives/ng_optimized_image_spec.ts | 33 ++++++++++---------
2 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/packages/common/src/directives/ng_optimized_image/preload-link-creator.ts b/packages/common/src/directives/ng_optimized_image/preload-link-creator.ts
index c4d2274dca08..f96b3dcddec0 100644
--- a/packages/common/src/directives/ng_optimized_image/preload-link-creator.ts
+++ b/packages/common/src/directives/ng_optimized_image/preload-link-creator.ts
@@ -10,7 +10,7 @@ import {
inject,
Injectable,
Renderer2,
- ɵRuntimeError as RuntimeError,
+ ɵformatRuntimeError as formatRuntimeError,
DOCUMENT,
} from '@angular/core';
@@ -30,6 +30,7 @@ import {DEFAULT_PRELOADED_IMAGES_LIMIT, PRELOADED_IMAGES} from './tokens';
export class PreloadLinkCreator {
private readonly preloadedImages = inject(PRELOADED_IMAGES);
private readonly document = inject(DOCUMENT);
+ private errorShown = false;
/**
* @description Add a preload `` to the `
` of the `index.html` that is served from the
@@ -48,17 +49,21 @@ export class PreloadLinkCreator {
* @param sizes The value of the `sizes` attribute passed in to the `` tag
*/
createPreloadLinkTag(renderer: Renderer2, src: string, srcset?: string, sizes?: string): void {
- if (ngDevMode) {
- if (this.preloadedImages.size >= DEFAULT_PRELOADED_IMAGES_LIMIT) {
- throw new RuntimeError(
+ if (
+ ngDevMode &&
+ !this.errorShown &&
+ this.preloadedImages.size >= DEFAULT_PRELOADED_IMAGES_LIMIT
+ ) {
+ this.errorShown = true;
+ console.warn(
+ formatRuntimeError(
RuntimeErrorCode.TOO_MANY_PRELOADED_IMAGES,
- ngDevMode &&
- `The \`NgOptimizedImage\` directive has detected that more than ` +
- `${DEFAULT_PRELOADED_IMAGES_LIMIT} images were marked as priority. ` +
- `This might negatively affect an overall performance of the page. ` +
- `To fix this, remove the "priority" attribute from images with less priority.`,
- );
- }
+ `The \`NgOptimizedImage\` directive has detected that more than ` +
+ `${DEFAULT_PRELOADED_IMAGES_LIMIT} images were marked as priority. ` +
+ `This might negatively affect an overall performance of the page. ` +
+ `To fix this, remove the "priority" attribute from images with less priority.`,
+ ),
+ );
}
if (this.preloadedImages.has(src)) {
diff --git a/packages/common/test/directives/ng_optimized_image_spec.ts b/packages/common/test/directives/ng_optimized_image_spec.ts
index 61252aa46678..762b43008966 100644
--- a/packages/common/test/directives/ng_optimized_image_spec.ts
+++ b/packages/common/test/directives/ng_optimized_image_spec.ts
@@ -141,7 +141,7 @@ describe('Image directive', () => {
preloadLinks[0]!.remove();
});
- it('should error when the number of preloaded images is larger than the limit', () => {
+ it('should warn when the number of preloaded images is larger than the limit', () => {
// Only run this test in a browser since the Node-based DOM mocks don't
// allow to override `HTMLImageElement.prototype.setAttribute` easily.
if (!isBrowser) return;
@@ -157,22 +157,23 @@ describe('Image directive', () => {
});
const template = `
-
-
-
-
-
-
-
-
-
- `;
+
+
+
+
+
+
+
+
+
+ `;
- expect(() => {
- const fixture = createTestComponent(template);
- fixture.detectChanges();
- }).toThrowError(
- 'NG02961: The `NgOptimizedImage` directive has detected that more than 5 images were marked as priority. This might negatively affect an overall performance of the page. To fix this, remove the "priority" attribute from images with less priority.',
+ const consoleWarnSpy = spyOn(console, 'warn');
+ const fixture = createTestComponent(template);
+ fixture.detectChanges();
+ expect(consoleWarnSpy.calls.count()).toBe(1);
+ expect(consoleWarnSpy.calls.argsFor(0)[0]).toMatch(
+ /NG02961: The `NgOptimizedImage` directive has detected that more than 5 images were marked as priority/,
);
});
});