diff --git a/.pullapprove.yml b/.pullapprove.yml index 6a0be66cb63..6d67f5632f2 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -266,6 +266,8 @@ groups: 'aio/content/images/guide/frequent-ngmodules/**/{*,.*}', 'aio/content/guide/hierarchical-dependency-injection.md', 'aio/content/examples/hierarchical-dependency-injection/**/{*,.*}', + 'aio/content/guide/image-directive.md', + 'aio/content/guide/image-directive-setup.md', 'aio/content/examples/providers-viewproviders/**/{*,.*}', 'aio/content/examples/resolution-modifiers/**/{*,.*}', 'aio/content/guide/lazy-loading-ngmodules.md', diff --git a/aio/content/guide/image-directive-setup.md b/aio/content/guide/image-directive-setup.md new file mode 100644 index 00000000000..2a6233ed5df --- /dev/null +++ b/aio/content/guide/image-directive-setup.md @@ -0,0 +1,96 @@ +# Setting up `NgOptimizedImage` + +This tutorial explains how to setup the `NgOptimizedImage`. For information on using `NgOptimizedImage`, see [Getting Started with NgOptimizedImage](/guide/image-directive). + +## Import `NgOptimizedImage` + +You can import `NgOptimizedImage` from the `@angular/common` module. The directive is defined as a [standalone directive](/guide/standalone-components), so components should import it directly. + +## Configure an `ImageLoader` + +A "loader" is a function that generates the [image transformation URL](https://web.dev/image-cdns/#how-image-cdns-use-urls-to-indicate-optimization-options) for a given image file. When appropriate, `NgOptimzedImage` sets the size, format, and image quality transformations for an image. + +`NgOptimizedImage` provides a generic loader as well as loaders for various third-party image services; it also supports writing your own custom loader. + +| Loader type| Behavior | +|:--- |:--- | +| Generic loader | The URL returned by the generic loader will always match the value of `src`. In other words, this loader applies no transformations. Sites that use Angular to serve images are the primary intended use case for this loader.| +| Loaders for third-party image services | The URL returned by the loaders for third-party image services will follow API conventions used by that particular image service. | +| Custom loaders | A custom loader's behavior is defined by its developer. You should use a custom loader if your image service isn't supported by the loaders that come preconfigured with `NgOptimzedImage`.| + +Based on the image services commonly used with Angular applications, `NgOptimizedImage` provides loaders preconfigured to work with the following image services: + +| Image Service | Angular API | Documentation | +|:--- |:--- |:--- | +| Cloudflare Image Resizing | `provideCloudflareLoader` | [Documentation](https://developers.cloudflare.com/images/image-resizing/) | +| Cloudinary | `provideCloudinaryLoader` | [Documentation](https://developers.cloudflare.com/images/image-resizing/) | | +| ImageKit | `provideImageKitLoader` | [Documentation](https://docs.imagekit.io/) | +| Imgix | `provideImgixLoader` | [Documentation](https://docs.imgix.com/) | + +You must configure an image loader to use `NgOptimizedImage`. + +These instructions explain how to setup an image loader for use with the `NgOptimizedImage`. + +1. Import the `NgOptimizedImage` directive into the application by adding it to the `imports` section of an NgModule or a standalone Component. + + +import { NgOptimizedImage } from '@angular/common'; +// Include NgOptimizedImage in the appropriate NgModule +@NgModule({ + imports: [ + // ... other imports + NgOptimizedImage, + ], +}) + +class AppModule {} + + + +@Component({ + standalone: true, + imports: [ + // ... other imports + NgOptimizedImage, + ], +}) + +class MyStandaloneComponent {} + + +2. Configure a loader that you want to use. + +To use the **generic loader**: no additional code changes are necessary. + +To use an existing loader for a **third-party image service**: add the provider factory for your chosen service to the `providers` array. In the example below, the Imgix loader is used: + + +providers: [ + provideImgixLoader('https://my.base.url/'), +], + + +The base URL for your image assets should be passed to the provider factory as an argument. For most sites, this base URL should match one of the following patterns: + +* https://yoursite.yourcdn.com +* https://subdomain.yoursite.com +* https://subdomain.yourcdn.com/yoursite + +You can learn more about the base URL structure in the docs of a corresponding CDN provider. + +To use a **custom loader**: provide your loader function as a value for the `IMAGE_LOADER` DI token. In the example below, the custom loader function returns a URL starting with `https://example.com` that includes `src` and `width` as URL parameters. + + +providers: [ + { + provide: IMAGE_LOADER, + useValue: (config: ImageLoaderConfig) => { + return `https://example.com/images?src=${config.src}&width=${config.width}`; + }, + }, +], + + +A loader function for the `NgOptimizedImage` directive takes an object with the `ImageLoaderConfig` type (from `@angular/common`) as its argument and returns the absolute URL of the image asset. The `ImageLoaderConfig` object contains the `src`and `width` properties. + +Note: a custom loader must support requesting images at various widths in order for `rawSrcset` to work properly. \ No newline at end of file diff --git a/aio/content/guide/image-directive.md b/aio/content/guide/image-directive.md new file mode 100644 index 00000000000..052b045c516 --- /dev/null +++ b/aio/content/guide/image-directive.md @@ -0,0 +1,99 @@ +# Getting started with NgOptimizedImage + +Note: the `NgOptimizedImage` directive is currently in the [“Developer Preview” mode](https://angular.io/guide/releases#developer-preview). The Angular team will stabilize the APIs based on the feedback and will make an announcement once the APIs are fully stable. + +The `NgOptimizedImage` directive makes it easy to adopt performance best practices for loading images. + +The `NgOptimizedImage` directive ensures that the loading of the [Largest Contentful Paint](http://web.dev/lcp) image is prioritized by: + +* Automatically setting the `fetchpriority` attribute on the `` tag +* Lazy loading other images by default +* Asserting that there is a corresponding preconnect link tag in the document head + +In addition to optimizing the loading of the LCP image, `NgOptimizedImage` enforces a number of image best practices: + +* Using [image URLs to apply image optimizations](https://web.dev/image-cdns/#how-image-cdns-use-urls-to-indicate-optimization-options) +* Requires that `width` and `height` are set +* Warns if `width` or `height` have been set incorrectly +* Warns if the image will be visually distorted when rendered + +## Prerequisites + +You will need to import the directive into your application. In addition, you will need to setup an image loader. These steps are explained in the [Setting up `NgOptimizedImage`](/guide/image-directive-setup) tutorial. + +## Usage in a template + +### Overview + +To activate the `NgOptimizedImage` directive, replace your image's `src` attribute with `rawSrc`. + + + + + +The built-in third-party loaders prepend a shared base URL to `src`. If you're using one of these loaders (or any other loader that does this), make sure to omit the shared base URL path from `src` to prevent unnecessary duplication. + +You must also set the `width` and `height` attributes. This is done to prevent [image-related layout shifts](https://web.dev/css-web-vitals/#images-and-layout-shifts). The `width` and `height` attributes should reflect the [intrinsic size](https://developer.mozilla.org/en-US/docs/Glossary/Intrinsic_Size) of the image. During development, the `NgOptimizedImage` warns if it detects that the `width` and `height` attributes have been set incorrectly. + +### Marking images as `priority` + +Always mark the [LCP image](https://web.dev/lcp/#what-elements-are-considered) on your page as `priority` to prioritize its loading. + + + + + +Marking an image as `priority` applies the following optimizations: + +* Sets `fetchpriority=high` (read more about priority hints [here](https://web.dev/priority-hints/)) +* Sets `loading=eager` (read more about native lazy loading [here](https://web.dev/browser-level-image-lazy-loading/)) + +Angular displays a warning during development if the LCP element is an image that does not have the `priority` attribute. A page’s LCP element can vary based on a number of factors - such as the dimensions of a user's screen. A page may have multiple images that should be marked `priority`. See [CSS for Web Vitals](https://web.dev/css-web-vitals/#images-and-largest-contentful-paint-lcp) for more details. + +### Adding resource hints + +You can add a [`preconnect` resource hint](https://web.dev/preconnect-and-dns-prefetch/) for your image origin to ensure that the LCP image loads as quickly as possible. Always put resource hints in the `` of the document. + + + + + +By default, if you use a loader for a third-party image service, the `NgOptimizedImage` directive will warn during development if it detects that there is no `preconnect` resource hint for the origin that serves the LCP image. + +To disable these warnings, add `{ensurePreconnect: false}` to the arguments passed to the provider factory for your chosen image service: + + +providers: [ + provideImgixLoader('https://my.base.url', {ensurePreconnect: false}) +], + + +### Adjusting image styling + +Depending on the image's styling, adding `width` and `height` attributes may cause the image to render differently. `NgOptimizedImage` warns you if your image styling renders the image at a distorted aspect ratio. + +You can typically fix this by adding `height: auto` or `width: auto` to your image styles. For more information, see the [web.dev article on the `` tag](https://web.dev/patterns/web-vitals-patterns/images/img-tag/). + +### Handling `srcset` attributes + +If your `` tag defines a `srcset` attribute, replace it with `rawSrcset`. + + + + + +If the `rawSrcset` attribute is present, `NgOptimizedImage` generates and sets the [`srcset` attribute](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset) using the configured image loader. Do not include image file names in `rawSrcset` - the directive infers this information from `rawSrc`. The directive supports both width descriptors (e.g. `100w`) and density descriptors (e.g. `1x`) are supported. + +You can also use `rawSrcset` with the standard image [`sizes` attribute](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes). + + + + + +### Disabling image lazy loading + +By default, `NgOptimizedImage` sets `loading=lazy` for all images that are not marked `priority`. You can disable this behavior for non-priority images by setting the `loading` attribute. This attribute accepts values: `eager`, `auto`, and `lazy`. [See the documentation for the standard image `loading` attribute for details](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/loading#value). + + + + diff --git a/aio/content/navigation.json b/aio/content/navigation.json index 176491533bb..933ef0273ca 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -637,6 +637,11 @@ "url": "guide/prerendering", "title": "Prerendering", "tooltip": "Prerender HTML server-side with Angular Universal." + }, + { + "url": "guide/image-directive", + "title": "Image Directive", + "tooltip": "Performant images with the Angular image directive." } ] }, @@ -816,7 +821,12 @@ "tooltip": "Create a template-driven form using directives and Angular template syntax." }, { - "title": "Angular libraries", + "url": "guide/image-directive-setup", + "title": "Setting up NgOptimzedImage", + "tooltip": "Setup the Angular image directive" + }, + { + "title": "Angular Libraries", "tooltip": "Extending Angular with shared libraries.", "children": [ {