Skip to content

Commit

Permalink
Fix multiple images being generated for the same image (#6710)
Browse files Browse the repository at this point in the history
* fix(images): Fix multiple calls to same image generating multiple images

* chore: changeset
  • Loading branch information
Princesseuh authored Mar 30, 2023
1 parent b1b9b13 commit a0bdf4c
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/new-coats-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fix multiple Image / getImage calls with the same image causing multiple duplicate images to be generated
4 changes: 3 additions & 1 deletion packages/astro/src/assets/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ export async function getImage(options: ImageTransform): Promise<GetImageResult>
};
}

export function getStaticImageList(): Iterable<[ImageTransform, string]> {
export function getStaticImageList(): Iterable<
[string, { path: string; options: ImageTransform }]
> {
if (!globalThis?.astroAsset?.staticImages) {
return [];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/assets/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ declare global {
var astroAsset: {
imageService?: ImageService;
addStaticImage?: ((options: ImageTransform) => string) | undefined;
staticImages?: Map<ImageTransform, string>;
staticImages?: Map<string, { path: string; options: ImageTransform }>;
};
}

Expand Down
10 changes: 7 additions & 3 deletions packages/astro/src/assets/utils/transformToPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ import { shorthash } from '../../runtime/server/shorthash.js';
import { isESMImportedImage } from '../internal.js';
import type { ImageTransform } from '../types.js';

export function propsToFilename(transform: ImageTransform, imageService: string) {
export function propsToFilename(transform: ImageTransform, hash: string) {
if (!isESMImportedImage(transform.src)) {
return transform.src;
}

let filename = removeQueryString(transform.src.src);
const ext = extname(filename);
filename = basename(filename, ext);
const outputExt = transform.format ? `.${transform.format}` : ext;
return `/${filename}_${hash}${outputExt}`;
}

export function hashTransform(transform: ImageTransform, imageService: string) {
// take everything from transform except alt, which is not used in the hash
const { alt, ...rest } = transform;
const hashFields = { ...rest, imageService };
const outputExt = transform.format ? `.${transform.format}` : ext;
return `/${filename}_${shorthash(JSON.stringify(hashFields))}${outputExt}`;
return shorthash(JSON.stringify(hashFields));
}
20 changes: 11 additions & 9 deletions packages/astro/src/assets/vite-plugin-assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { copyWasmFiles } from './services/vendor/squoosh/copy-wasm.js';
import { emitESMImage } from './utils/emitAsset.js';
import { imageMetadata } from './utils/metadata.js';
import { getOrigQueryParams } from './utils/queryParams.js';
import { propsToFilename } from './utils/transformToPath.js';
import { hashTransform, propsToFilename } from './utils/transformToPath.js';

const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;

Expand Down Expand Up @@ -153,12 +153,17 @@ export default function assets({

globalThis.astroAsset.addStaticImage = (options) => {
if (!globalThis.astroAsset.staticImages) {
globalThis.astroAsset.staticImages = new Map<ImageTransform, string>();
globalThis.astroAsset.staticImages = new Map<
string,
{ path: string; options: ImageTransform }
>();
}

const hash = hashTransform(options, settings.config.image.service);

let filePath: string;
if (globalThis.astroAsset.staticImages.has(options)) {
filePath = globalThis.astroAsset.staticImages.get(options)!;
if (globalThis.astroAsset.staticImages.has(hash)) {
filePath = globalThis.astroAsset.staticImages.get(hash)!.path;
} else {
// If the image is not imported, we can return the path as-is, since static references
// should only point ot valid paths for builds or remote images
Expand All @@ -167,12 +172,9 @@ export default function assets({
}

filePath = prependForwardSlash(
joinPaths(
settings.config.build.assets,
propsToFilename(options, settings.config.image.service)
)
joinPaths(settings.config.build.assets, propsToFilename(options, hash))
);
globalThis.astroAsset.staticImages.set(options, filePath);
globalThis.astroAsset.staticImages.set(hash, { path: filePath, options: options });
}

return prependForwardSlash(joinPaths(settings.config.base, filePath));
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
if (opts.settings.config.experimental.assets) {
info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`);
for (const imageData of getStaticImageList()) {
await generateImage(opts, imageData[0], imageData[1]);
await generateImage(opts, imageData[1].options, imageData[1].path);
}
delete globalThis.astroAsset.addStaticImage;
}
Expand Down

0 comments on commit a0bdf4c

Please sign in to comment.