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/, ); }); });