From 4516d7b22c5979cde4537f196b53ae2826ba9561 Mon Sep 17 00:00:00 2001
From: Erika <3019731+Princesseuh@users.noreply.github.com>
Date: Tue, 16 May 2023 16:40:32 +0200
Subject: [PATCH] refactor(assets): Move generation logic out of internal.ts
 (#7102)

---
 .changeset/brown-goats-serve.md           |   5 +
 packages/astro/src/assets/generate.ts     | 126 ++++++++++++++++++++++
 packages/astro/src/assets/internal.ts     | 125 +--------------------
 packages/astro/src/core/build/generate.ts |   2 +-
 4 files changed, 133 insertions(+), 125 deletions(-)
 create mode 100644 .changeset/brown-goats-serve.md
 create mode 100644 packages/astro/src/assets/generate.ts

diff --git a/.changeset/brown-goats-serve.md b/.changeset/brown-goats-serve.md
new file mode 100644
index 000000000..19574439c
--- /dev/null
+++ b/.changeset/brown-goats-serve.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fix image services not being usable on Edge runtimes
diff --git a/packages/astro/src/assets/generate.ts b/packages/astro/src/assets/generate.ts
new file mode 100644
index 000000000..25493753a
--- /dev/null
+++ b/packages/astro/src/assets/generate.ts
@@ -0,0 +1,126 @@
+import fs from 'node:fs';
+import { basename, join } from 'node:path/posix';
+import type { StaticBuildOptions } from '../core/build/types.js';
+import { warn } from '../core/logger/core.js';
+import { prependForwardSlash } from '../core/path.js';
+import { getConfiguredImageService, isESMImportedImage } from './internal.js';
+import type { LocalImageService } from './services/service.js';
+import type { ImageTransform } from './types.js';
+
+interface GenerationDataUncached {
+	cached: false;
+	weight: {
+		before: number;
+		after: number;
+	};
+}
+
+interface GenerationDataCached {
+	cached: true;
+}
+
+type GenerationData = GenerationDataUncached | GenerationDataCached;
+
+export async function generateImage(
+	buildOpts: StaticBuildOptions,
+	options: ImageTransform,
+	filepath: string
+): Promise<GenerationData | undefined> {
+	if (!isESMImportedImage(options.src)) {
+		return undefined;
+	}
+
+	let useCache = true;
+	const assetsCacheDir = new URL('assets/', buildOpts.settings.config.cacheDir);
+
+	// Ensure that the cache directory exists
+	try {
+		await fs.promises.mkdir(assetsCacheDir, { recursive: true });
+	} catch (err) {
+		warn(
+			buildOpts.logging,
+			'astro:assets',
+			`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
+		);
+		useCache = false;
+	}
+
+	let serverRoot: URL, clientRoot: URL;
+	if (buildOpts.settings.config.output === 'server') {
+		serverRoot = buildOpts.settings.config.build.server;
+		clientRoot = buildOpts.settings.config.build.client;
+	} else {
+		serverRoot = buildOpts.settings.config.outDir;
+		clientRoot = buildOpts.settings.config.outDir;
+	}
+
+	const finalFileURL = new URL('.' + filepath, clientRoot);
+	const finalFolderURL = new URL('./', finalFileURL);
+	const cachedFileURL = new URL(basename(filepath), assetsCacheDir);
+
+	try {
+		await fs.promises.copyFile(cachedFileURL, finalFileURL);
+
+		return {
+			cached: true,
+		};
+	} catch (e) {
+		// no-op
+	}
+
+	// The original file's path (the `src` attribute of the ESM imported image passed by the user)
+	const originalImagePath = options.src.src;
+
+	const fileData = await fs.promises.readFile(
+		new URL(
+			'.' +
+				prependForwardSlash(
+					join(buildOpts.settings.config.build.assets, basename(originalImagePath))
+				),
+			serverRoot
+		)
+	);
+
+	const imageService = (await getConfiguredImageService()) as LocalImageService;
+	const resultData = await imageService.transform(
+		fileData,
+		{ ...options, src: originalImagePath },
+		buildOpts.settings.config.image.service.config
+	);
+
+	await fs.promises.mkdir(finalFolderURL, { recursive: true });
+
+	if (useCache) {
+		try {
+			await fs.promises.writeFile(cachedFileURL, resultData.data);
+			await fs.promises.copyFile(cachedFileURL, finalFileURL);
+		} catch (e) {
+			warn(
+				buildOpts.logging,
+				'astro:assets',
+				`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
+			);
+			await fs.promises.writeFile(finalFileURL, resultData.data);
+		}
+	} else {
+		await fs.promises.writeFile(finalFileURL, resultData.data);
+	}
+
+	return {
+		cached: false,
+		weight: {
+			before: Math.trunc(fileData.byteLength / 1024),
+			after: Math.trunc(resultData.data.byteLength / 1024),
+		},
+	};
+}
+
+export function getStaticImageList(): Iterable<
+	[string, { path: string; options: ImageTransform }]
+> {
+	if (!globalThis?.astroAsset?.staticImages) {
+		return [];
+	}
+
+	return globalThis.astroAsset.staticImages?.entries();
+}
diff --git a/packages/astro/src/assets/internal.ts b/packages/astro/src/assets/internal.ts
index 2a7d08ff7..2d4d18ea7 100644
--- a/packages/astro/src/assets/internal.ts
+++ b/packages/astro/src/assets/internal.ts
@@ -1,10 +1,5 @@
-import fs from 'node:fs';
-import { basename, join } from 'node:path/posix';
-import type { StaticBuildOptions } from '../core/build/types.js';
 import { AstroError, AstroErrorData } from '../core/errors/index.js';
-import { warn } from '../core/logger/core.js';
-import { prependForwardSlash } from '../core/path.js';
-import { isLocalService, type ImageService, type LocalImageService } from './services/service.js';
+import { isLocalService, type ImageService } from './services/service.js';
 import type { GetImageResult, ImageMetadata, ImageTransform } from './types.js';
 
 export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata {
@@ -63,121 +58,3 @@ export async function getImage(
 				: {},
 	};
 }
-
-export function getStaticImageList(): Iterable<
-	[string, { path: string; options: ImageTransform }]
-> {
-	if (!globalThis?.astroAsset?.staticImages) {
-		return [];
-	}
-
-	return globalThis.astroAsset.staticImages?.entries();
-}
-
-interface GenerationDataUncached {
-	cached: false;
-	weight: {
-		before: number;
-		after: number;
-	};
-}
-
-interface GenerationDataCached {
-	cached: true;
-}
-
-type GenerationData = GenerationDataUncached | GenerationDataCached;
-
-export async function generateImage(
-	buildOpts: StaticBuildOptions,
-	options: ImageTransform,
-	filepath: string
-): Promise<GenerationData | undefined> {
-	if (!isESMImportedImage(options.src)) {
-		return undefined;
-	}
-
-	let useCache = true;
-	const assetsCacheDir = new URL('assets/', buildOpts.settings.config.cacheDir);
-
-	// Ensure that the cache directory exists
-	try {
-		await fs.promises.mkdir(assetsCacheDir, { recursive: true });
-	} catch (err) {
-		warn(
-			buildOpts.logging,
-			'astro:assets',
-			`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${err}`
-		);
-		useCache = false;
-	}
-
-	let serverRoot: URL, clientRoot: URL;
-	if (buildOpts.settings.config.output === 'server') {
-		serverRoot = buildOpts.settings.config.build.server;
-		clientRoot = buildOpts.settings.config.build.client;
-	} else {
-		serverRoot = buildOpts.settings.config.outDir;
-		clientRoot = buildOpts.settings.config.outDir;
-	}
-
-	const finalFileURL = new URL('.' + filepath, clientRoot);
-	const finalFolderURL = new URL('./', finalFileURL);
-	const cachedFileURL = new URL(basename(filepath), assetsCacheDir);
-
-	try {
-		await fs.promises.copyFile(cachedFileURL, finalFileURL);
-
-		return {
-			cached: true,
-		};
-	} catch (e) {
-		// no-op
-	}
-
-	// The original file's path (the `src` attribute of the ESM imported image passed by the user)
-	const originalImagePath = options.src.src;
-
-	const fileData = await fs.promises.readFile(
-		new URL(
-			'.' +
-				prependForwardSlash(
-					join(buildOpts.settings.config.build.assets, basename(originalImagePath))
-				),
-			serverRoot
-		)
-	);
-
-	const imageService = (await getConfiguredImageService()) as LocalImageService;
-	const resultData = await imageService.transform(
-		fileData,
-		{ ...options, src: originalImagePath },
-		buildOpts.settings.config.image.service.config
-	);
-
-	await fs.promises.mkdir(finalFolderURL, { recursive: true });
-
-	if (useCache) {
-		try {
-			await fs.promises.writeFile(cachedFileURL, resultData.data);
-			await fs.promises.copyFile(cachedFileURL, finalFileURL);
-		} catch (e) {
-			warn(
-				buildOpts.logging,
-				'astro:assets',
-				`An error was encountered while creating the cache directory. Proceeding without caching. Error: ${e}`
-			);
-			await fs.promises.writeFile(finalFileURL, resultData.data);
-		}
-	} else {
-		await fs.promises.writeFile(finalFileURL, resultData.data);
-	}
-
-	return {
-		cached: false,
-		weight: {
-			before: Math.trunc(fileData.byteLength / 1024),
-			after: Math.trunc(resultData.data.byteLength / 1024),
-		},
-	};
-}
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index 8d195bab4..8a85232c4 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -19,7 +19,7 @@ import type {
 import {
 	generateImage as generateImageInternal,
 	getStaticImageList,
-} from '../../assets/internal.js';
+} from '../../assets/generate.js';
 import { hasPrerenderedPages, type BuildInternals } from '../../core/build/internal.js';
 import {
 	prependForwardSlash,