1// Alchemy modifications are licensed under Apache-2.0.
2// This file includes third-party code; see /THIRD_PARTY_LICENSES.md.
3/**
4 * Vendored from `@astrojs/cloudflare` v14.1.3 (`src/utils/static-image-collection.ts`).
5 *
6 * Installs `globalThis.astroAsset.addStaticImage` for use inside workerd
7 * during prerendering. This mirrors the logic in astro's vite-plugin-assets.ts
8 * but uses only workerd-safe APIs (no node: imports).
9 */
10import {
11 joinPaths,
12 prependForwardSlash,
13 removeBase,
14} from "@astrojs/internal-helpers/path";
15import { hashTransform, propsToFilename } from "astro/assets";
16import { isESMImportedImage } from "astro/assets/utils";
17
18/** Mirrors `CompileImageConfig` from the config plugin (`virtual:astro-cloudflare:config`). */
19export interface CompileImageConfig {
20 base: string;
21 assetsPrefix: string | undefined;
22 imageServiceEntrypoint: string;
23 buildAssets: string;
24}
25
26export function installAddStaticImage(config: CompileImageConfig): void {
27 if (globalThis.astroAsset?.addStaticImage) return;
28
29 if (!globalThis.astroAsset) {
30 globalThis.astroAsset = { referencedImages: new Set() };
31 }
32
33 globalThis.astroAsset.addStaticImage = (
34 options,
35 hashProperties,
36 _originalFSPath,
37 ) => {
38 if (!globalThis.astroAsset.staticImages) {
39 globalThis.astroAsset.staticImages = new Map();
40 }
41
42 const ESMImportedImageSrc = isESMImportedImage(options.src)
43 ? options.src.src
44 : options.src;
45
46 const finalOriginalPath = removeBase(
47 removeBase(ESMImportedImageSrc, config.base),
48 config.assetsPrefix ?? "",
49 );
50
51 const hash = hashTransform(
52 options,
53 config.imageServiceEntrypoint,
54 hashProperties,
55 );
56
57 let finalFilePath: string;
58 let transformsForPath =
59 globalThis.astroAsset.staticImages.get(finalOriginalPath);
60 const transformForHash = transformsForPath?.transforms.get(hash);
61
62 if (transformsForPath && transformForHash) {
63 finalFilePath = transformForHash.finalPath;
64 } else {
65 finalFilePath = prependForwardSlash(
66 joinPaths(
67 isESMImportedImage(options.src) ? "" : config.buildAssets,
68 prependForwardSlash(
69 propsToFilename(finalOriginalPath, options, hash),
70 ),
71 ),
72 );
73
74 if (!transformsForPath) {
75 globalThis.astroAsset.staticImages.set(finalOriginalPath, {
76 originalSrcPath: _originalFSPath,
77 transforms: new Map(),
78 });
79 transformsForPath =
80 globalThis.astroAsset.staticImages.get(finalOriginalPath)!;
81 }
82
83 transformsForPath.transforms.set(hash, {
84 finalPath: finalFilePath,
85 transform: options,
86 });
87 }
88
89 // Build the final URL the same way the Vite plugin does
90 if (config.assetsPrefix) {
91 return encodeURI(joinPaths(config.assetsPrefix, finalFilePath));
92 }
93 return encodeURI(
94 prependForwardSlash(joinPaths(config.base, finalFilePath)),
95 );
96 };
97}