feat(image): Export more types and utilities for users to use (#6739)
This commit is contained in:
parent
4c347ab51e
commit
2f2e572e93
13 changed files with 57 additions and 38 deletions
5
.changeset/unlucky-emus-learn.md
Normal file
5
.changeset/unlucky-emus-learn.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Added more types and utilities exports related to `astro:assets` to help building custom image components and image services
|
|
@ -30,8 +30,20 @@ export type {
|
||||||
RemarkPlugins,
|
RemarkPlugins,
|
||||||
ShikiConfig,
|
ShikiConfig,
|
||||||
} from '@astrojs/markdown-remark';
|
} from '@astrojs/markdown-remark';
|
||||||
export type { ExternalImageService, LocalImageService } from '../assets/services/service';
|
export type {
|
||||||
export type { ImageMetadata, ImageTransform } from '../assets/types';
|
ExternalImageService,
|
||||||
|
ImageService,
|
||||||
|
LocalImageService,
|
||||||
|
} from '../assets/services/service';
|
||||||
|
export type {
|
||||||
|
GetImageResult,
|
||||||
|
ImageInputFormat,
|
||||||
|
ImageMetadata,
|
||||||
|
ImageOutputFormat,
|
||||||
|
ImageQuality,
|
||||||
|
ImageQualityPreset,
|
||||||
|
ImageTransform,
|
||||||
|
} from '../assets/types';
|
||||||
export type { SSRManifest } from '../core/app/types';
|
export type { SSRManifest } from '../core/app/types';
|
||||||
export type { AstroCookies } from '../core/cookies';
|
export type { AstroCookies } from '../core/cookies';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export { getConfiguredImageService, getImage } from './internal.js';
|
export { getConfiguredImageService, getImage } from './internal.js';
|
||||||
export { baseService } from './services/service.js';
|
export { baseService, isLocalService } from './services/service.js';
|
||||||
export { type LocalImageProps, type RemoteImageProps } from './types.js';
|
export { type LocalImageProps, type RemoteImageProps } from './types.js';
|
||||||
export { emitESMImage } from './utils/emitAsset.js';
|
export { emitESMImage } from './utils/emitAsset.js';
|
||||||
export { imageMetadata } from './utils/metadata.js';
|
export { imageMetadata } from './utils/metadata.js';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import type { StaticBuildOptions } from '../core/build/types.js';
|
||||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||||
import { prependForwardSlash } from '../core/path.js';
|
import { prependForwardSlash } from '../core/path.js';
|
||||||
import { isLocalService, type ImageService, type LocalImageService } from './services/service.js';
|
import { isLocalService, type ImageService, type LocalImageService } from './services/service.js';
|
||||||
import type { ImageMetadata, ImageTransform } from './types.js';
|
import type { GetImageResult, ImageMetadata, ImageTransform } from './types.js';
|
||||||
|
|
||||||
export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata {
|
export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata {
|
||||||
return typeof src === 'object';
|
return typeof src === 'object';
|
||||||
|
@ -29,13 +29,6 @@ export async function getConfiguredImageService(): Promise<ImageService> {
|
||||||
return globalThis.astroAsset.imageService;
|
return globalThis.astroAsset.imageService;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetImageResult {
|
|
||||||
rawOptions: ImageTransform;
|
|
||||||
options: ImageTransform;
|
|
||||||
src: string;
|
|
||||||
attributes: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an optimized image and the necessary attributes to render it.
|
* Get an optimized image and the necessary attributes to render it.
|
||||||
*
|
*
|
||||||
|
@ -45,7 +38,7 @@ interface GetImageResult {
|
||||||
* import { getImage } from 'astro:assets';
|
* import { getImage } from 'astro:assets';
|
||||||
* import originalImage from '../assets/image.png';
|
* import originalImage from '../assets/image.png';
|
||||||
*
|
*
|
||||||
* const optimizedImage = await getImage({src: originalImage, width: 1280 })
|
* const optimizedImage = await getImage({src: originalImage, width: 1280 });
|
||||||
* ---
|
* ---
|
||||||
* <img src={optimizedImage.src} {...optimizedImage.attributes} />
|
* <img src={optimizedImage.src} {...optimizedImage.attributes} />
|
||||||
* ```
|
* ```
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
|
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
|
||||||
import { VALID_INPUT_FORMATS } from '../consts.js';
|
import { VALID_INPUT_FORMATS } from '../consts.js';
|
||||||
import { isESMImportedImage } from '../internal.js';
|
import { isESMImportedImage } from '../internal.js';import type { ImageOutputFormat, ImageTransform } from '../types.js';
|
||||||
import type { ImageTransform, OutputFormat } from '../types.js';
|
|
||||||
|
|
||||||
export type ImageService = LocalImageService | ExternalImageService;
|
export type ImageService = LocalImageService | ExternalImageService;
|
||||||
|
|
||||||
|
@ -71,7 +70,7 @@ export interface LocalImageService extends SharedServiceProps {
|
||||||
transform: (
|
transform: (
|
||||||
inputBuffer: Buffer,
|
inputBuffer: Buffer,
|
||||||
transform: LocalImageTransform
|
transform: LocalImageTransform
|
||||||
) => Promise<{ data: Buffer; format: OutputFormat }>;
|
) => Promise<{ data: Buffer; format: ImageOutputFormat }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BaseServiceTransform = {
|
export type BaseServiceTransform = {
|
||||||
|
@ -204,7 +203,7 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
src: params.get('href')!,
|
src: params.get('href')!,
|
||||||
width: params.has('w') ? parseInt(params.get('w')!) : undefined,
|
width: params.has('w') ? parseInt(params.get('w')!) : undefined,
|
||||||
height: params.has('h') ? parseInt(params.get('h')!) : undefined,
|
height: params.has('h') ? parseInt(params.get('h')!) : undefined,
|
||||||
format: params.get('f') as OutputFormat,
|
format: params.get('f') as ImageOutputFormat,
|
||||||
quality: params.get('q'),
|
quality: params.get('q'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { FormatEnum } from 'sharp';
|
import type { FormatEnum } from 'sharp';
|
||||||
import type { ImageQualityPreset, OutputFormat } from '../types.js';
|
import type { ImageOutputFormat, ImageQualityPreset } from '../types.js';
|
||||||
import {
|
import {
|
||||||
baseService,
|
baseService,
|
||||||
parseQuality,
|
parseQuality,
|
||||||
|
@ -64,7 +64,7 @@ const sharpService: LocalImageService = {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: data,
|
data: data,
|
||||||
format: info.format as OutputFormat,
|
format: info.format as ImageOutputFormat,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// TODO: Investigate removing this service once sharp lands WASM support, as libsquoosh is deprecated
|
// TODO: Investigate removing this service once sharp lands WASM support, as libsquoosh is deprecated
|
||||||
|
|
||||||
import type { ImageQualityPreset, OutputFormat } from '../types.js';
|
import type { ImageOutputFormat, ImageQualityPreset } from '../types.js';
|
||||||
import {
|
import {
|
||||||
baseService,
|
baseService,
|
||||||
parseQuality,
|
parseQuality,
|
||||||
|
@ -11,7 +11,10 @@ import { processBuffer } from './vendor/squoosh/image-pool.js';
|
||||||
import type { Operation } from './vendor/squoosh/image.js';
|
import type { Operation } from './vendor/squoosh/image.js';
|
||||||
|
|
||||||
const baseQuality = { low: 25, mid: 50, high: 80, max: 100 };
|
const baseQuality = { low: 25, mid: 50, high: 80, max: 100 };
|
||||||
const qualityTable: Record<Exclude<OutputFormat, 'png'>, Record<ImageQualityPreset, number>> = {
|
const qualityTable: Record<
|
||||||
|
Exclude<ImageOutputFormat, 'png'>,
|
||||||
|
Record<ImageQualityPreset, number>
|
||||||
|
> = {
|
||||||
avif: {
|
avif: {
|
||||||
// Squoosh's AVIF encoder has a bit of a weird behavior where `62` is technically the maximum, and anything over is overkill
|
// Squoosh's AVIF encoder has a bit of a weird behavior where `62` is technically the maximum, and anything over is overkill
|
||||||
max: 62,
|
max: 62,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { isMainThread } from 'node:worker_threads';
|
import { isMainThread } from 'node:worker_threads';
|
||||||
import { cpus } from 'os';
|
import { cpus } from 'os';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type { OutputFormat } from '../../../types.js';
|
import type { ImageOutputFormat } from '../../../types.js';
|
||||||
import { getModuleURL } from './emscripten-utils.js';
|
import { getModuleURL } from './emscripten-utils.js';
|
||||||
import type { Operation } from './image.js';
|
import type { Operation } from './image.js';
|
||||||
import * as impl from './impl.js';
|
import * as impl from './impl.js';
|
||||||
|
@ -88,7 +88,7 @@ function handleJob(params: JobMessage) {
|
||||||
export async function processBuffer(
|
export async function processBuffer(
|
||||||
buffer: Buffer,
|
buffer: Buffer,
|
||||||
operations: Operation[],
|
operations: Operation[],
|
||||||
encoding: OutputFormat,
|
encoding: ImageOutputFormat,
|
||||||
quality?: number
|
quality?: number
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { OutputFormat } from '../../../types.js';
|
import type { ImageOutputFormat } from '../../../types.js';
|
||||||
import * as impl from './impl.js';
|
import * as impl from './impl.js';
|
||||||
|
|
||||||
type RotateOperation = {
|
type RotateOperation = {
|
||||||
|
@ -15,7 +15,7 @@ export type Operation = RotateOperation | ResizeOperation
|
||||||
export async function processBuffer(
|
export async function processBuffer(
|
||||||
buffer: Buffer,
|
buffer: Buffer,
|
||||||
operations: Operation[],
|
operations: Operation[],
|
||||||
encoding: OutputFormat,
|
encoding: ImageOutputFormat,
|
||||||
quality?: number
|
quality?: number
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
let imageData = await impl.decodeBuffer(buffer)
|
let imageData = await impl.decodeBuffer(buffer)
|
||||||
|
|
|
@ -4,8 +4,8 @@ import type { ImageService } from './services/service.js';
|
||||||
|
|
||||||
export type ImageQualityPreset = 'low' | 'mid' | 'high' | 'max' | (string & {});
|
export type ImageQualityPreset = 'low' | 'mid' | 'high' | 'max' | (string & {});
|
||||||
export type ImageQuality = ImageQualityPreset | number;
|
export type ImageQuality = ImageQualityPreset | number;
|
||||||
export type InputFormat = (typeof VALID_INPUT_FORMATS)[number] | 'svg';
|
export type ImageInputFormat = (typeof VALID_INPUT_FORMATS)[number] | 'svg';
|
||||||
export type OutputFormat = (typeof VALID_OUTPUT_FORMATS)[number] | (string & {});
|
export type ImageOutputFormat = (typeof VALID_OUTPUT_FORMATS)[number] | (string & {});
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line no-var
|
// eslint-disable-next-line no-var
|
||||||
|
@ -23,7 +23,7 @@ export interface ImageMetadata {
|
||||||
src: string;
|
src: string;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
format: InputFormat;
|
format: ImageInputFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,13 +31,20 @@ export interface ImageMetadata {
|
||||||
*/
|
*/
|
||||||
export type ImageTransform = {
|
export type ImageTransform = {
|
||||||
src: ImageMetadata | string;
|
src: ImageMetadata | string;
|
||||||
width?: number;
|
width?: number | undefined;
|
||||||
height?: number;
|
height?: number | undefined;
|
||||||
quality?: ImageQuality;
|
quality?: ImageQuality | undefined;
|
||||||
format?: OutputFormat;
|
format?: ImageOutputFormat | undefined;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface GetImageResult {
|
||||||
|
rawOptions: ImageTransform;
|
||||||
|
options: ImageTransform;
|
||||||
|
src: string;
|
||||||
|
attributes: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
|
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
|
||||||
type ImageSharedProps<T> = T & {
|
type ImageSharedProps<T> = T & {
|
||||||
/**
|
/**
|
||||||
|
@ -94,11 +101,11 @@ export type LocalImageProps<T> = ImageSharedProps<T> & {
|
||||||
* <Image src={...} format="avif" alt="..." />
|
* <Image src={...} format="avif" alt="..." />
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
format?: OutputFormat;
|
format?: ImageOutputFormat;
|
||||||
/**
|
/**
|
||||||
* Desired quality for the image. Value can either be a preset such as `low` or `high`, or a numeric value from 0 to 100.
|
* Desired quality for the image. Value can either be a preset such as `low` or `high`, or a numeric value from 0 to 100.
|
||||||
*
|
*
|
||||||
* The perceptual quality of the output image is loader-specific.
|
* The perceptual quality of the output image is service-specific.
|
||||||
* For instance, a certain service might decide that `high` results in a very beautiful image, but another could choose for it to be at best passable.
|
* For instance, a certain service might decide that `high` results in a very beautiful image, but another could choose for it to be at best passable.
|
||||||
*
|
*
|
||||||
* **Example**:
|
* **Example**:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import type { ImageMetadata, InputFormat } from '../types.js';
|
import type { ImageInputFormat, ImageMetadata } from '../types.js';
|
||||||
import imageSize from '../vendor/image-size/index.js';
|
import imageSize from '../vendor/image-size/index.js';
|
||||||
|
|
||||||
export interface Metadata extends ImageMetadata {
|
export interface Metadata extends ImageMetadata {
|
||||||
|
@ -31,7 +31,7 @@ export async function imageMetadata(
|
||||||
src: fileURLToPath(src),
|
src: fileURLToPath(src),
|
||||||
width: isPortrait ? height : width,
|
width: isPortrait ? height : width,
|
||||||
height: isPortrait ? width : height,
|
height: isPortrait ? width : height,
|
||||||
format: type as InputFormat,
|
format: type as ImageInputFormat,
|
||||||
orientation,
|
orientation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { ImageMetadata, InputFormat } from '../types.js';
|
import type { ImageInputFormat, ImageMetadata } from '../types.js';
|
||||||
|
|
||||||
export function getOrigQueryParams(
|
export function getOrigQueryParams(
|
||||||
params: URLSearchParams
|
params: URLSearchParams
|
||||||
|
@ -14,6 +14,6 @@ export function getOrigQueryParams(
|
||||||
return {
|
return {
|
||||||
width: parseInt(width),
|
width: parseInt(width),
|
||||||
height: parseInt(height),
|
height: parseInt(height),
|
||||||
format: format as InputFormat,
|
format: format as ImageInputFormat,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ export default function assets({
|
||||||
load(id) {
|
load(id) {
|
||||||
if (id === resolvedVirtualModuleId) {
|
if (id === resolvedVirtualModuleId) {
|
||||||
return `
|
return `
|
||||||
export { getImage, getConfiguredImageService } from "astro/assets";
|
export { getImage, getConfiguredImageService, isLocalService } from "astro/assets";
|
||||||
export { default as Image } from "astro/components/Image.astro";
|
export { default as Image } from "astro/components/Image.astro";
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue