Skip to content

Commit

Permalink
implement astro
Browse files Browse the repository at this point in the history
  • Loading branch information
ascorbic committed Dec 17, 2024
1 parent 543237d commit 44b82b4
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 42 deletions.
8 changes: 7 additions & 1 deletion examples/astro/src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
import { Image } from "@unpic/astro";
import { Image as BaseImage } from "@unpic/astro/base";
import { transform } from "unpic/providers/imgix";
import lighthouse from "../formentor.jpg";
---

Expand All @@ -13,12 +15,16 @@ import lighthouse from "../formentor.jpg";
</head>
<body style="margin:0">
<div>
<Image
<BaseImage
src="https://images.unsplash.com/photo-1617718295766-0f839c2853e7"
layout="fullWidth"
alt="fullWidth"
aspectRatio={16 / 9}
priority
transformer={transform}
operations={{
sepia: 50,
}}
/>
<Image
src={lighthouse}
Expand Down
2 changes: 0 additions & 2 deletions packages/astro/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
// @ts-expect-error - Astro imports don't work with TypeScript libs :(
export { default as Image } from "./src/Image.astro";
// @ts-expect-error - Astro imports don't work with TypeScript libs :(
export { default as Source } from "./src/Source.astro";
1 change: 1 addition & 0 deletions packages/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"homepage": "https://unpic.pics/img/astro",
"exports": {
".": "./index.ts",
"./base": "./src/base.ts",
"./service": "./src/service.ts"
},
"files": [
Expand Down
11 changes: 6 additions & 5 deletions packages/astro/src/Image.astro
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ const config: UnpicConfig = imageConfig.service?.config;
imgProps.layout ||= config?.layout;
imgProps.background ||= placeholder ?? config?.placeholder;
if (!imgProps.cdn) {
imgProps.cdn = getDefaultImageCdn(config);
}
imgProps.background = await getBackground(imgProps);
if (imgProps.cdn === "astro") {
imgProps.cdnOptions = getEndpointOptions(imageConfig, imgProps.cdnOptions);
if (!imgProps.cdn && !imgProps.fallback) {
imgProps.fallback = getDefaultImageCdn(config);
}
if (imgProps.cdn === "astro" || imgProps.fallback === "astro") {
imgProps.options = getEndpointOptions(imageConfig, imgProps.options);
}
---

Expand Down
12 changes: 5 additions & 7 deletions packages/astro/src/Source.astro
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ const config: UnpicConfig = imageConfig.service?.config;
sourceProps.layout ||= config?.layout;
if (!sourceProps.cdn) {
sourceProps.cdn = getDefaultImageCdn(config);
if (!sourceProps.cdn && !sourceProps.fallback) {
sourceProps.fallback = getDefaultImageCdn(config);
}
if (sourceProps.cdn === "astro") {
sourceProps.cdnOptions = getEndpointOptions(
imageConfig,
sourceProps.cdnOptions,
);
if (sourceProps.cdn === "astro" || sourceProps.fallback === "astro") {
sourceProps.options = getEndpointOptions(imageConfig, sourceProps.options);
}
console.log(sourceProps);
---

<source {...transformSourceProps(sourceProps)} />
30 changes: 18 additions & 12 deletions packages/astro/src/background.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { UnpicImageProps } from "@unpic/core";
import {
getCanonicalCdnForUrl,
getProviderForUrl,
transformUrl,
type UrlTransformerOptions,
} from "unpic";
Expand Down Expand Up @@ -38,26 +38,29 @@ export async function getBackground(
}
}

const cdn = getCanonicalCdnForUrl(props.src, props.cdn);
const cdn = getProviderForUrl(props.src) ?? props.fallback;

if (!cdn) {
return;
}

const bgImgProps: UrlTransformerOptions = {
...props,
url: props.src,
width: 12,
height: 12 * aspectRatio,
cdn: cdn.cdn,
fallback: props.fallback,
cdn,
};

if (!cdn) {
return;
}

if (props.background === "lqip") {
const lowUrl = transformUrl(bgImgProps)?.toString();
const lowUrl = transformUrl(
bgImgProps,
props.operations,
props.options,
)?.toString();

if (!lowUrl) {
return;
Expand All @@ -78,11 +81,15 @@ export async function getBackground(
return "data:" + contentType + ";base64," + buffer.toString("base64");
}

const lowUrl = transformUrl({
...bgImgProps,
width: 100,
height: 100 * aspectRatio,
})?.toString();
const lowUrl = transformUrl(
{
...bgImgProps,
width: 100,
height: 100 * aspectRatio,
},
props.operations,
props.options,
)?.toString();

if (!lowUrl) {
return;
Expand All @@ -91,7 +98,6 @@ export async function getBackground(
if (!isValidUrl(lowUrl)) {
return;
}

const pixels = await getPixels(lowUrl);

if (!pixels) {
Expand Down
2 changes: 2 additions & 0 deletions packages/astro/src/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Image } from "./base/Image.astro";
export { default as Source } from "./base/Source.astro";
62 changes: 62 additions & 0 deletions packages/astro/src/base/Image.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
import { imageConfig } from "astro:assets";
import type { Operations, UnpicBaseImageProps } from "@unpic/core";
import {
inferImageDimensions,
transformBaseImageProps,
} from "@unpic/core/base";
import type { ImageMetadata } from "astro";
import type { HTMLAttributes } from "astro/types";
import { getBackground } from "../background";
import type { UnpicConfig } from "../service";
type Props<
TOperations extends Operations = Operations,
TOptions = unknown,
> = Omit<
UnpicBaseImageProps<TOperations, TOptions, astroHTML.JSX.ImgHTMLAttributes>,
"src"
> & {
placeholder?: "none" | "blurhash" | "dominantColor" | "lqip" | ({} & string);
src: string | ImageMetadata;
};
const { placeholder, ...props }: Props = Astro.props;
type BaseImageProps = UnpicBaseImageProps<
Operations,
unknown,
HTMLAttributes<"img">
>;
let imgProps: BaseImageProps;
if (typeof props.src === "object") {
imgProps = {
...props,
src: props.src.src,
...inferImageDimensions(props, props.src),
} as BaseImageProps;
} else {
imgProps = {
...props,
} as BaseImageProps;
}
const config: UnpicConfig = imageConfig.service?.config;
imgProps.layout ||= config?.layout;
imgProps.background ||= placeholder ?? config?.placeholder;
imgProps.background = await getBackground(imgProps);
---

<img
{...transformBaseImageProps<
Operations,
unknown,
astroHTML.JSX.ImgHTMLAttributes,
astroHTML.JSX.ImgHTMLAttributes["style"]
>(imgProps)}
/>
36 changes: 36 additions & 0 deletions packages/astro/src/base/Source.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
import { imageConfig } from "astro:assets";
import type { Operations, UnpicBaseSourceProps } from "@unpic/core";
import type { UnpicConfig } from "../service";
import {
transformBaseSourceProps,
inferImageDimensions,
} from "@unpic/core/base";
type Props<TOperations extends Operations, TOptions> = Omit<
UnpicBaseSourceProps<TOperations, TOptions>,
"src"
> & {
src: string | ImageMetadata;
};
const props = Astro.props as Props<Operations, unknown>;
let sourceProps: UnpicBaseSourceProps<Operations, unknown>;
if (typeof props.src === "object") {
sourceProps = {
...props,
src: props.src.src,
...inferImageDimensions(props, props.src),
} as UnpicBaseSourceProps<Operations, unknown>;
} else {
sourceProps = props as UnpicBaseSourceProps<Operations, unknown>;
}
const config: UnpicConfig = imageConfig.service?.config;
sourceProps.layout ||= config?.layout;
---

<source {...transformBaseSourceProps(sourceProps)} />
12 changes: 6 additions & 6 deletions packages/astro/src/service/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
inferImageDimensions,
normalizeImageType,
transformProps,
type ConstrainedImageProps,
type UnpicImageProps,
} from "@unpic/core";
import type { ExternalImageService, ImageTransform } from "astro";
import type { UnpicConfig } from "../service.ts";
Expand All @@ -15,7 +15,7 @@ import { getEndpointOptions } from "../utils.ts";
* Tries to detect a default image service based on the environment.
*/
export function getDefaultService(): ImageCdn {
if (env.NETLIFY || env.NETLIFY_LOCAL) {
if (env.NETLIFY || env.NETLIFY_LOCAL || "Netlify" in globalThis) {
return "netlify";
}
if (env.VERCEL || env.NOW_BUILDER) {
Expand Down Expand Up @@ -71,14 +71,14 @@ const service: ExternalImageService<UnpicConfig> = {
const cdnOptions = getEndpointOptions(imageConfig);
const entries = getSrcSetEntries({
...transformOptions,
cdnOptions,
options: cdnOptions,
src: transformOptions.url,
});
return entries.map(({ width, height }) => ({
transform: {
...options,
width,
height,
width: Number(width),
height: Number(height),
},
descriptor: `${width}w`,
attributes,
Expand Down Expand Up @@ -112,7 +112,7 @@ const service: ExternalImageService<UnpicConfig> = {
const { src, srcset, ...props } = transformProps({
...transformOptions,
src: transformOptions.url.toString(),
} as ConstrainedImageProps<
} as UnpicImageProps<
astroHTML.JSX.ImgHTMLAttributes,
astroHTML.JSX.ImgHTMLAttributes["style"]
>);
Expand Down
3 changes: 1 addition & 2 deletions packages/astro/src/service/sharp.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { LocalImageService } from "astro";
import baseService from "./base.ts";
import sharpImageService from "astro/assets/services/sharp";
import type { UnpicConfig } from "../service.ts";

const service: LocalImageService<UnpicConfig> = {
const service: LocalImageService = {
...baseService,
transform: sharpImageService.transform,
parseURL: sharpImageService.parseURL,
Expand Down
13 changes: 6 additions & 7 deletions packages/astro/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { UnpicConfig } from "./service";
import { getDefaultService } from "./service/base";
import type { CdnOptions, ImageCdn } from "unpic";
import type { ProviderOptions, ImageCdn } from "unpic";
import type { AstroConfig } from "astro";

export function getDefaultImageCdn(config: UnpicConfig): ImageCdn {
Expand All @@ -15,14 +15,13 @@ export function getDefaultImageCdn(config: UnpicConfig): ImageCdn {

export function getEndpointOptions(
imageConfig: AstroConfig["image"],
cdnOptions: CdnOptions = {},
): CdnOptions {
cdnOptions.astro ??= {};
cdnOptions.astro.endpoint =
options: Partial<ProviderOptions> = {},
): Partial<ProviderOptions> {
options.astro ??= {};
options.astro.endpoint =
typeof imageConfig?.endpoint === "object"
? // The astro types are wrong here
(imageConfig?.endpoint as any)?.route
: imageConfig?.endpoint;

return cdnOptions;
return options;
}

0 comments on commit 44b82b4

Please sign in to comment.