Fix multiple images being generated for the same image (#6710)
* fix(images): Fix multiple calls to same image generating multiple images * chore: changeset
This commit is contained in:
parent
b1b9b1390f
commit
a0bdf4ce2f
6 changed files with 28 additions and 15 deletions
5
.changeset/new-coats-check.md
Normal file
5
.changeset/new-coats-check.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix multiple Image / getImage calls with the same image causing multiple duplicate images to be generated
|
|
@ -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) {
|
if (!globalThis?.astroAsset?.staticImages) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ declare global {
|
||||||
var astroAsset: {
|
var astroAsset: {
|
||||||
imageService?: ImageService;
|
imageService?: ImageService;
|
||||||
addStaticImage?: ((options: ImageTransform) => string) | undefined;
|
addStaticImage?: ((options: ImageTransform) => string) | undefined;
|
||||||
staticImages?: Map<ImageTransform, string>;
|
staticImages?: Map<string, { path: string; options: ImageTransform }>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { shorthash } from '../../runtime/server/shorthash.js';
|
||||||
import { isESMImportedImage } from '../internal.js';
|
import { isESMImportedImage } from '../internal.js';
|
||||||
import type { ImageTransform } from '../types.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)) {
|
if (!isESMImportedImage(transform.src)) {
|
||||||
return transform.src;
|
return transform.src;
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,13 @@ export function propsToFilename(transform: ImageTransform, imageService: string)
|
||||||
let filename = removeQueryString(transform.src.src);
|
let filename = removeQueryString(transform.src.src);
|
||||||
const ext = extname(filename);
|
const ext = extname(filename);
|
||||||
filename = basename(filename, ext);
|
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
|
// take everything from transform except alt, which is not used in the hash
|
||||||
const { alt, ...rest } = transform;
|
const { alt, ...rest } = transform;
|
||||||
const hashFields = { ...rest, imageService };
|
const hashFields = { ...rest, imageService };
|
||||||
const outputExt = transform.format ? `.${transform.format}` : ext;
|
return shorthash(JSON.stringify(hashFields));
|
||||||
return `/${filename}_${shorthash(JSON.stringify(hashFields))}${outputExt}`;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { copyWasmFiles } from './services/vendor/squoosh/copy-wasm.js';
|
||||||
import { emitESMImage } from './utils/emitAsset.js';
|
import { emitESMImage } from './utils/emitAsset.js';
|
||||||
import { imageMetadata } from './utils/metadata.js';
|
import { imageMetadata } from './utils/metadata.js';
|
||||||
import { getOrigQueryParams } from './utils/queryParams.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;
|
const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
||||||
|
|
||||||
|
@ -153,12 +153,17 @@ export default function assets({
|
||||||
|
|
||||||
globalThis.astroAsset.addStaticImage = (options) => {
|
globalThis.astroAsset.addStaticImage = (options) => {
|
||||||
if (!globalThis.astroAsset.staticImages) {
|
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;
|
let filePath: string;
|
||||||
if (globalThis.astroAsset.staticImages.has(options)) {
|
if (globalThis.astroAsset.staticImages.has(hash)) {
|
||||||
filePath = globalThis.astroAsset.staticImages.get(options)!;
|
filePath = globalThis.astroAsset.staticImages.get(hash)!.path;
|
||||||
} else {
|
} else {
|
||||||
// If the image is not imported, we can return the path as-is, since static references
|
// 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
|
// should only point ot valid paths for builds or remote images
|
||||||
|
@ -167,12 +172,9 @@ export default function assets({
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath = prependForwardSlash(
|
filePath = prependForwardSlash(
|
||||||
joinPaths(
|
joinPaths(settings.config.build.assets, propsToFilename(options, hash))
|
||||||
settings.config.build.assets,
|
|
||||||
propsToFilename(options, settings.config.image.service)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
globalThis.astroAsset.staticImages.set(options, filePath);
|
globalThis.astroAsset.staticImages.set(hash, { path: filePath, options: options });
|
||||||
}
|
}
|
||||||
|
|
||||||
return prependForwardSlash(joinPaths(settings.config.base, filePath));
|
return prependForwardSlash(joinPaths(settings.config.base, filePath));
|
||||||
|
|
|
@ -108,7 +108,7 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
|
||||||
if (opts.settings.config.experimental.assets) {
|
if (opts.settings.config.experimental.assets) {
|
||||||
info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`);
|
info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`);
|
||||||
for (const imageData of getStaticImageList()) {
|
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;
|
delete globalThis.astroAsset.addStaticImage;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue