From a741e34654349431e818e775a45bdf4863d718cc 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 (cherry picked from commit 8f25d4a0331908d1b47da38b1359dc8b3760ec42) --- .../preload-link-creator.ts | 33 ++++++++++++------- .../directives/ng_optimized_image_spec.ts | 33 ++++++++++--------- 2 files changed, 38 insertions(+), 28 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 91b317a023b5..6462009fefae 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 @@ -6,8 +6,12 @@ * found in the LICENSE file at https://angular.dev/license */ -import {inject, Injectable, Renderer2, ɵRuntimeError as RuntimeError} from '@angular/core'; - +import { + inject, + Injectable, + Renderer2, + ɵformatRuntimeError as formatRuntimeError, +} from '@angular/core'; import {DOCUMENT} from '../../dom_tokens'; import {RuntimeErrorCode} from '../../errors'; @@ -25,6 +29,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 @@ -43,17 +48,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 9bbc46a3114b..61253323ca59 100644 --- a/packages/common/test/directives/ng_optimized_image_spec.ts +++ b/packages/common/test/directives/ng_optimized_image_spec.ts @@ -140,7 +140,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; @@ -156,22 +156,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/, ); }); });