Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes type definitions @astrojs/image and adds more documentation to the README #4045

Merged
merged 22 commits into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 186 additions & 5 deletions packages/integrations/image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,190 @@ Then, restart the dev server.

## Usage

The included `sharp` transformer supports resizing images and encoding them to different image formats. Third-party image services will be able to add support for custom transformations as well (ex: `blur`, `filter`, `rotate`, etc).

### `<Image />`

The built-in `<Image />` component is used to create an optimized `<img />` for both remote images hosted on other domains as well as local images imported from your project's `src` directory.

The included `sharp` transformer supports resizing images and encoding them to different image formats. Third-party image services will be able to add support for custom transformations as well (ex: `blur`, `filter`, `rotate`, etc).
In addition to the component-specific properties, any valid HTML attribute for the `<img />` included in the `<Image />` component will be included in the built `<img />`.

#### src

<p>

**Type:** `string` | `ImageMetadata` | `Promise<ImageMetadata>`<br>
**Required:** `true`
</p>

Source for the original image file.

For images in your project's repository, use the `src` relative to the `public` directory. For remote images, provide the full URL.

#### format

<p>

**Type:** 'avif' | 'jpeg' | 'png' | 'webp'<br>
**Default:** `undefined`
</p>

The output format to be used in the optimized image. The original image format will be used if `format` is not provided.

#### quality

<p>

**Type:** `number`<br>
**Default:** `undefined`
</p>

The compression quality used during optimization. The image service will use a default quality if not provided.

#### width

<p>

**Type:** `number`<br>
**Default:** `undefined`
</p>

The desired width of the output image. Combine with `height` to crop the image to an exact size, or `aspectRatio` to automatically calculate and crop the height.

Dimensions are optional for local images, the original image size will be used if not provided.

For remote images, the integration needs to be able to calculate dimensions for the optimized image. This can be done by providing `width` and `height` or by providing one dimension and an `aspectRatio`.

#### height

<p>

**Type:** `number`<br>
**Default:** `undefined`
</p>

The desired height of the output image. Combine with `width` to crop the image to an exact size, or `aspectRatio` to automatically calculate and crop the width.

Dimensions are optional for local images, the original image size will be used if not provided.

For remote images, the integration needs to be able to calculate dimensions for the optimized image. This can be done by providing `width` and `height` or by providing one dimension and an `aspectRatio`.

#### aspectRatio

<p>

**Type:** `number` | `string`<br>
**Default:** `undefined`
</p>

The desired aspect ratio of the output image. Combine with either `width` or `height` to automatically calculate and crop the other dimension.

A `string` can be provided in the form of `{width}:{height}`, ex: `16:9` or `3:4`.

A `number` can also be provided, useful when the aspect ratio is calculated at build time. This can be an inline number such as `1.777` or inlined as a JSX expression like `aspectRatio={16/9}`.

### `<Picture /`>

#### src

<p>

**Type:** `string` | `ImageMetadata` | `Promise<ImageMetadata>`<br>
**Required:** `true`
</p>

Source for the original image file.

For images in your project's repository, use the `src` relative to the `public` directory. For remote images, provide the full URL.

#### alt

<p>

**Type:** `string`<br>
**Default:** `undefined
tony-sull marked this conversation as resolved.
Show resolved Hide resolved
</p>

If provided, the `alt` string will be included on the built `<img />` element.

#### sizes

<p>

**Type:** `string`<br>
**Required:** `true`
</p>

The HTMLImageElement property `sizes` allows you to specify the layout width of the image for each of a list of media conditions.

See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes) for more details.

#### widths

<p>

**Type:** `number[]`<br>
**Reuqired:** `true`
</p>

The list of sizes that should be built for responsive images. This is combined with `aspectRatio` to calculate the final dimensions of each built image.

```jsx
// Builds three images: 400x400, 800x800, and 1200x1200
<Picture src={...} widths={[400, 800, 1200]} aspectRatio="1:1" />
```

#### aspectRatio

<p>

**Type:** `number` | `string`<br>
**Required:** `true`
</p>

The desired aspect ratio of the output image. This is combined with `widhts` to calculate the final dimensions of each built image.

A `string` can be provided in the form of `{width}:{height}`, ex: `16:9` or `3:4`.

A `number` can also be provided, useful when the aspect ratio is calculated at build time. This can be an inline number such as `1.777` or inlined as a JSX expression like `aspectRatio={16/9}`.

#### formats

<p>

**Type:** Array<'avif' | 'jpeg' | 'png' | 'webp'><br>
**Default:** `undefined`
</p>

The output formats to be used in the optimized image. If not provided, `webp` and `avif` will be used in addition to the original image format.

### `getImage`

This is the helper function used by the `<Image />` component to build `<img />` attributes for the transformed image. This helper can be used directly for more complex use cases that aren't currently supported by the `<Image />` component.

This helper takes in an object with the same properties as the `<Image />` component and returns an object with attributes that should be included on the final `<img />` element.

This can helpful if you need to add preload links to a page's `<head>`.

```jsx
---
import { getImage } from '@astrojs/image';

const { src } = await getImage('../assets/hero.png');
---

<html>
<head>
<link rel="preload" as="image" href={src}>
</head>
</html>
```

### `getPicture`

This is the helper function used by the `<Picture />` component to build multiple sizes and formats for responsive images. This helper can be used directly for more complex use cases that aren't currently supported by the `<Picture />` component.

This helper takes in an object with the same properties as the `<Picture />` component and returns an object attributes that should be included on the final `<img />` element **and** a list of sources that should be used to render all `<source>`s for the `<picture>` element.

## Configuration

Expand Down Expand Up @@ -102,7 +283,7 @@ export default {

Image files in your project's `src` directory can be imported in frontmatter and passed directly to the `<Image />` component. All other properties are optional and will default to the original image file's properties if not provided.

```html
```jsx
tony-sull marked this conversation as resolved.
Show resolved Hide resolved
---
import { Image } from '@astrojs/image/components';
import heroImage from '../assets/hero.png';
Expand Down Expand Up @@ -130,7 +311,7 @@ import heroImage from '../assets/hero.png';

Remote images can be transformed with the `<Image />` component. The `<Image />` component needs to know the final dimensions for the `<img />` element to avoid content layout shifts. For remote images, this means you must either provide `width` and `height`, or one of the dimensions plus the required `aspectRatio`.

```html
```jsx
---
import { Image } from '@astrojs/image/components';

Expand All @@ -153,7 +334,7 @@ const imageUrl = 'https://www.google.com/images/branding/googlelogo/2x/googlelog

The `<Image />` component can also be used to optimize images in markdown pages. For local images imported from your project's `src` directory, use Astro's the `setup` frontmatter to import the image file.
tony-sull marked this conversation as resolved.
Show resolved Hide resolved

```html
```jsx
---
setup: |
import { Image } from '@astrojs/image/components'
Expand All @@ -179,7 +360,7 @@ description: Just a Hello World Post!

For remote images, an `aspectRatio` is required to ensure the correct `height` can be calculated at build time.

```html
```jsx
---
import { Picture } from '@astrojs/image/components';
import hero from '../assets/hero.png';
Expand Down
9 changes: 3 additions & 6 deletions packages/integrations/image/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Load and transform images in your Astro site.",
"version": "0.1.3",
"type": "module",
"types": "./dist/types.d.ts",
"types": "./types.d.ts",
"author": "withastro",
"license": "MIT",
"repository": {
Expand All @@ -20,10 +20,7 @@
"bugs": "https://github.com/withastro/astro/issues",
"homepage": "https://docs.astro.build/en/guides/integrations-guide/image/",
"exports": {
".": {
"astro": "./components/index.js",
"import": "./dist/index.js"
},
".": "./dist/index.js",
"./sharp": "./dist/loaders/sharp.js",
"./endpoints/dev": "./dist/endpoints/dev.js",
"./endpoints/prod": "./dist/endpoints/prod.js",
Expand All @@ -34,7 +31,7 @@
"components",
"dist",
"src",
"types"
"types.d.ts"
],
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
Expand Down
138 changes: 138 additions & 0 deletions packages/integrations/image/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/// <reference types="astro/astro-jsx" />
import type { AstroIntegration } from 'astro';
export * from './dist/index.js';

interface ImageIntegration {
loader?: ImageService;
addStaticImage?: (transform: TransformOptions) => void;
filenameFormat?: (transform: TransformOptions, searchParams: URLSearchParams) => string;
}

declare global {
// eslint-disable-next-line no-var
var astroImage: ImageIntegration | undefined;
}

export type InputFormat =
| 'heic'
| 'heif'
| 'avif'
| 'jpeg'
| 'jpg'
| 'png'
| 'tiff'
| 'webp'
| 'gif';

export type OutputFormat = 'avif' | 'jpeg' | 'png' | 'webp';

/**
* Converts a set of image transforms to the filename to use when building for static.
*
* This is only used for static production builds and ignored when an SSR adapter is used,
* or in `astro dev` for static builds.
*/
export type FilenameFormatter = (transform: TransformOptions) => string;

export interface IntegrationOptions {
/**
* Entry point for the @type {HostedImageService} or @type {LocalImageService} to be used.
*/
serviceEntryPoint?: string;
}

export default function image(options?: IntegrationOptions): AstroIntegration;

/**
* Defines the original image and transforms that need to be applied to it.
*/
export interface TransformOptions {
/**
* Source for the original image file.
*
* For images in your project's repository, use the `src` relative to the `public` directory.
* For remote images, provide the full URL.
*/
src: string;
/**
* The output format to be used in the optimized image.
*
* @default undefined The original image format will be used.
*/
format?: OutputFormat;
/**
* The compression quality used during optimization.
*
* @default undefined Allows the image service to determine defaults.
*/
quality?: number;
/**
* The desired width of the output image. Combine with `height` to crop the image
* to an exact size, or `aspectRatio` to automatically calculate and crop the height.
*/
width?: number;
/**
* The desired height of the output image. Combine with `height` to crop the image
* to an exact size, or `aspectRatio` to automatically calculate and crop the width.
*/
height?: number;
/**
* The desired aspect ratio of the output image. Combine with either `width` or `height`
* to automatically calculate and crop the other dimension.
*
* @example 1.777 - numbers can be used for computed ratios, useful for doing `{width/height}`
* @example "16:9" - strings can be used in the format of `{ratioWidth}:{ratioHeight}`.
*/
aspectRatio?: number | `${number}:${number}`;
}

export type ImageAttributes = astroHTML.JSX.ImgHTMLAttributes;
export type PictureAttributes = astroHTML.JSX.HTMLAttributes;

export interface HostedImageService<T extends TransformOptions = TransformOptions> {
/**
* Gets the HTML attributes needed for the server rendered `<img />` element.
*/
getImageAttributes(transform: T): Promise<ImageAttributes>;
}

export interface SSRImageService<T extends TransformOptions = TransformOptions>
extends HostedImageService<T> {
/**
* Gets tthe HTML attributes needed for the server rendered `<img />` element.
tony-sull marked this conversation as resolved.
Show resolved Hide resolved
*/
getImageAttributes(transform: T): Promise<Exclude<ImageAttributes, 'src'>>;
/**
* Serializes image transformation properties to URLSearchParams, used to build
* the final `src` that points to the self-hosted SSR endpoint.
*
* @param transform @type {TransformOptions} defining the requested image transformation.
*/
serializeTransform(transform: T): { searchParams: URLSearchParams };
/**
* The reverse of `serializeTransform(transform)`, this parsed the @type {TransformOptions} back out of a given URL.
*
* @param searchParams @type {URLSearchParams}
* @returns @type {TransformOptions} used to generate the URL, or undefined if the URL isn't valid.
*/
parseTransform(searchParams: URLSearchParams): T | undefined;
/**
* Performs the image transformations on the input image and returns both the binary data and
* final image format of the optimized image.
*
* @param inputBuffer Binary buffer containing the original image.
* @param transform @type {TransformOptions} defining the requested transformations.
*/
transform(inputBuffer: Buffer, transform: T): Promise<{ data: Buffer; format: OutputFormat }>;
}

export type ImageService<T extends TransformOptions = TransformOptions> =
| HostedImageService<T>
| SSRImageService<T>;

export interface ImageMetadata {
src: string;
width: number;
height: number;
format: InputFormat;
}