summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Tony Sullivan <tony.f.sullivan@outlook.com> 2022-07-18 19:43:40 +0000
committerGravatar GitHub <noreply@github.com> 2022-07-18 19:43:40 +0000
commit2a7dd040e8a65d62fbb3bbd7308f523bd48deda5 (patch)
tree3b091a486ae32977adb632ad34557d428720029c
parenteee14b5e5ff4221877d58e3fddbe26593f7a419e (diff)
downloadastro-2a7dd040e8a65d62fbb3bbd7308f523bd48deda5.tar.gz
astro-2a7dd040e8a65d62fbb3bbd7308f523bd48deda5.tar.zst
astro-2a7dd040e8a65d62fbb3bbd7308f523bd48deda5.zip
Improving support for third-party hosted image services (#3957)
* WIP: always use the built-in sharp service for local images in `dev` * adding type definitions for the integration's use of globalThis * simplifying the globalThis type checking * chore: adding changeset * removing temp hosted service used for testing
-rw-r--r--.changeset/purple-vans-bake.md5
-rw-r--r--packages/integrations/image/README.md2
-rw-r--r--packages/integrations/image/src/endpoints/dev.ts4
-rw-r--r--packages/integrations/image/src/get-image.ts27
-rw-r--r--packages/integrations/image/src/index.ts24
-rw-r--r--packages/integrations/image/src/types.ts12
6 files changed, 59 insertions, 15 deletions
diff --git a/.changeset/purple-vans-bake.md b/.changeset/purple-vans-bake.md
new file mode 100644
index 000000000..3af99ba74
--- /dev/null
+++ b/.changeset/purple-vans-bake.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/image': patch
+---
+
+Improves the `astro dev` experience when using a third-party hosted image service
diff --git a/packages/integrations/image/README.md b/packages/integrations/image/README.md
index b14587d71..ee9fdf3c9 100644
--- a/packages/integrations/image/README.md
+++ b/packages/integrations/image/README.md
@@ -73,6 +73,8 @@ The included `sharp` transformer supports resizing images and encoding them to d
The intergration can be configured to run with a different image service, either a hosted image service or a full image transformer that runs locally in your build or SSR deployment.
+> During development, local images may not have been published yet and would not be available to hosted image services. Local images will always use the built-in `sharp` service when using `astro dev`.
+
There are currently no other configuration options for the `@astrojs/image` integration. Please [open an issue](https://github.com/withastro/astro/issues/new/choose) if you have a compelling use case to share.
<details>
diff --git a/packages/integrations/image/src/endpoints/dev.ts b/packages/integrations/image/src/endpoints/dev.ts
index 3d8b28993..67b37b177 100644
--- a/packages/integrations/image/src/endpoints/dev.ts
+++ b/packages/integrations/image/src/endpoints/dev.ts
@@ -1,10 +1,10 @@
import type { APIRoute } from 'astro';
import { lookup } from 'mrmime';
-// @ts-ignore
-import loader from 'virtual:image-loader';
import { loadImage } from '../utils.js';
export const get: APIRoute = async ({ request }) => {
+ const loader = globalThis.astroImage.ssrLoader;
+
try {
const url = new URL(request.url);
const transform = loader.parseTransform(url.searchParams);
diff --git a/packages/integrations/image/src/get-image.ts b/packages/integrations/image/src/get-image.ts
index 5eb41cf73..83ac2e5ba 100644
--- a/packages/integrations/image/src/get-image.ts
+++ b/packages/integrations/image/src/get-image.ts
@@ -8,7 +8,7 @@ import {
OutputFormat,
TransformOptions,
} from './types.js';
-import { parseAspectRatio } from './utils.js';
+import { isRemoteImage, parseAspectRatio } from './utils.js';
export interface GetImageTransform extends Omit<TransformOptions, 'src'> {
src: string | ImageMetadata | Promise<{ default: ImageMetadata }>;
@@ -105,23 +105,32 @@ export async function getImage(
loader: ImageService,
transform: GetImageTransform
): Promise<ImageAttributes> {
- (globalThis as any).loader = loader;
+ globalThis.astroImage.loader = loader;
const resolved = await resolveTransform(transform);
+
const attributes = await loader.getImageAttributes(resolved);
+ const isDev = globalThis.astroImage.command === 'dev';
+ const isLocalImage = !isRemoteImage(resolved.src);
+
+ const _loader = isDev && isLocalImage ? globalThis.astroImage.ssrLoader : loader;
+
+ if (!_loader) {
+ throw new Error('@astrojs/image: loader not found!');
+ }
+
// For SSR services, build URLs for the injected route
- if (isSSRService(loader)) {
- const { searchParams } = loader.serializeTransform(resolved);
+ if (isSSRService(_loader)) {
+ const { searchParams } = _loader.serializeTransform(resolved);
// cache all images rendered to HTML
- if (globalThis && (globalThis as any).addStaticImage) {
- (globalThis as any)?.addStaticImage(resolved);
+ if (globalThis?.astroImage) {
+ globalThis.astroImage.addStaticImage(resolved);
}
- const src =
- globalThis && (globalThis as any).filenameFormat
- ? (globalThis as any).filenameFormat(resolved, searchParams)
+ const src = globalThis?.astroImage
+ ? globalThis.astroImage.filenameFormat(resolved, searchParams)
: `${ROUTE_PATTERN}?${searchParams.toString()}`;
return {
diff --git a/packages/integrations/image/src/index.ts b/packages/integrations/image/src/index.ts
index 3721f9667..da1ec1d4b 100644
--- a/packages/integrations/image/src/index.ts
+++ b/packages/integrations/image/src/index.ts
@@ -3,6 +3,7 @@ import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import { OUTPUT_DIR, PKG_NAME, ROUTE_PATTERN } from './constants.js';
+import sharp from './loaders/sharp.js';
import { IntegrationOptions, TransformOptions } from './types.js';
import {
ensureDir,
@@ -51,15 +52,15 @@ const createIntegration = (options: IntegrationOptions = {}): AstroIntegration =
// Used to cache all images rendered to HTML
// Added to globalThis to share the same map in Node and Vite
- (globalThis as any).addStaticImage = (transform: TransformOptions) => {
+ function addStaticImage(transform: TransformOptions) {
staticImages.set(propsToFilename(transform), transform);
};
// TODO: Add support for custom, user-provided filename format functions
- (globalThis as any).filenameFormat = (
+ function filenameFormat(
transform: TransformOptions,
searchParams: URLSearchParams
- ) => {
+ ) {
if (mode === 'ssg') {
return isRemoteImage(transform.src)
? path.join(OUTPUT_DIR, path.basename(propsToFilename(transform)))
@@ -73,6 +74,16 @@ const createIntegration = (options: IntegrationOptions = {}): AstroIntegration =
}
};
+ // Initialize the integration's globalThis namespace
+ // This is needed to share scope between Node and Vite
+ globalThis.astroImage = {
+ loader: undefined, // initialized in first getImage() call
+ ssrLoader: sharp,
+ command,
+ addStaticImage,
+ filenameFormat,
+ }
+
if (mode === 'ssr') {
injectRoute({
pattern: ROUTE_PATTERN,
@@ -83,7 +94,12 @@ const createIntegration = (options: IntegrationOptions = {}): AstroIntegration =
},
'astro:build:done': async ({ dir }) => {
for await (const [filename, transform] of staticImages) {
- const loader = (globalThis as any).loader;
+ const loader = globalThis.astroImage.loader;
+
+ if (!loader || !('transform' in loader)) {
+ // this should never be hit, how was a staticImage added without an SSR service?
+ return;
+ }
let inputBuffer: Buffer | undefined = undefined;
let outputFile: string;
diff --git a/packages/integrations/image/src/types.ts b/packages/integrations/image/src/types.ts
index 96067e828..e6c315c23 100644
--- a/packages/integrations/image/src/types.ts
+++ b/packages/integrations/image/src/types.ts
@@ -2,6 +2,18 @@
export type { Image, Picture } from '../components/index.js';
export * from './index.js';
+interface ImageIntegration {
+ loader?: ImageService;
+ ssrLoader: SSRImageService;
+ command: 'dev' | 'build';
+ addStaticImage: (transform: TransformOptions) => void;
+ filenameFormat: (transform: TransformOptions, searchParams: URLSearchParams) => string;
+}
+
+declare global {
+ var astroImage: ImageIntegration;
+}
+
export type InputFormat =
| 'heic'
| 'heif'