fix:imagetools

This commit is contained in:
lovebird 2025-03-18 10:09:29 +01:00
parent 0f6bcc4267
commit a64acb9f71
11 changed files with 141 additions and 138 deletions

File diff suppressed because one or more lines are too long

8
package-lock.json generated
View File

@ -67,6 +67,7 @@
"sharp": "^0.29.3",
"showdown": "^2.1.0",
"tailwindcss": "^4.0.7",
"ts-retry": "^6.0.0",
"type-fest": "^4.34.1",
"vite": "^6.1.1",
"vite-plugin-compression": "^0.5.1",
@ -15132,6 +15133,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/ts-retry": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/ts-retry/-/ts-retry-6.0.0.tgz",
"integrity": "sha512-WsVRE/P+VNYbiQC3E6TeIXBRCQj7vzjN4MlXd84AC88K7WwuWShN7A3Q/QSV/yd1hjO8qn2Cevdqny2HMwKUaA==",
"license": "MIT"
},
"node_modules/tsconfck": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.5.tgz",
@ -16759,6 +16766,7 @@
"license": "MIT",
"dependencies": {
"@astropub/codecs": "0.4.4",
"@polymech/fs": "file:../../../polymech-mono/packages/fs",
"file-type": "17.1.1",
"find-cache-dir": "3.3.2",
"find-up": "^6.3.0",

View File

@ -3,6 +3,9 @@
"version": "0.0.1",
"private": true,
"type": "module",
"exports": {
".": "./src/index.js"
},
"scripts": {
"dev": "astro dev --mode dev --host=0.0.0.0 --o-images=medium",
"start": "astro dev",
@ -77,6 +80,7 @@
"sharp": "^0.29.3",
"showdown": "^2.1.0",
"tailwindcss": "^4.0.7",
"ts-retry": "^6.0.0",
"type-fest": "^4.34.1",
"vite": "^6.1.1",
"vite-plugin-compression": "^0.5.1",

View File

@ -4,12 +4,7 @@ import objectHash from "object-hash";
import getImageSources from "./getImageSources.js";
import getProcessedImage from "./getProcessedImage.js";
import getArtDirectedImages from "./getArtDirectedImages.js";
import pMap from "p-map";
const imagesData = new Map();
const delay = (ms = 100) => new Promise((resolve) => setTimeout(resolve, ms));
export default async function ({
src,
type,
@ -23,76 +18,62 @@ export default async function ({
artDirectives,
transformConfigs,
}) {
try {
const args = Array.from(arguments);
const hash = objectHash(args);
if (imagesData.has(hash)) {
return imagesData.get(hash);
}
// const start = performance.now();
const { path, base, rest, image, imageWidth, imageHeight, imageFormat } =
await getProcessedImage(src, transformConfigs);
const args = Array.from(arguments);
await delay();
src = path;
const hash = objectHash(args);
rest.aspect = `${imageWidth / imageHeight}`;
if (!fallbackFormat) {
fallbackFormat = imageFormat;
}
// Fetch both image sources and art-directed images
const [mainImage, artDirectedImages] = await pMap(
[
async () =>
await getImageSources(
src,
base,
image,
format,
imageWidth,
imagesizes,
breakpoints,
placeholder,
imageFormat,
formatOptions,
fallbackFormat,
includeSourceFormat,
rest
),
async () => {
return await getArtDirectedImages(
artDirectives,
placeholder,
format,
imagesizes,
breakpoints,
fallbackFormat,
includeSourceFormat,
formatOptions,
rest
);
},
],
async (task) => await task(),
{ concurrency: 1 }
);
// Ensure artDirectedImages is an array
const images = Array.isArray(artDirectedImages) ? [...artDirectedImages, mainImage] : [mainImage];
const uuid = crypto.randomBytes(4).toString("hex").toUpperCase();
const returnObject = {
uuid,
images,
};
imagesData.set(hash, returnObject);
//const end = performance.now();
//console.log( `Responsive Image sets generated for ${type} at ${args[0].src} in ${end - start}ms`);
return returnObject;
} catch (error) {
console.error("Error processing images:", error);
debugger
throw error;
if (imagesData.has(hash)) {
return imagesData.get(hash);
}
const { path, base, rest, image, imageWidth, imageHeight, imageFormat } =
await getProcessedImage(src, transformConfigs);
src = path;
rest.aspect = `${imageWidth / imageHeight}`;
if (!fallbackFormat) {
fallbackFormat = imageFormat;
}
const [mainImage, artDirectedImages] = await Promise.all([
getImageSources(
src,
base,
image,
format,
imageWidth,
imagesizes,
breakpoints,
placeholder,
imageFormat,
formatOptions,
fallbackFormat,
includeSourceFormat,
rest
),
getArtDirectedImages(
artDirectives,
placeholder,
format,
imagesizes,
breakpoints,
fallbackFormat,
includeSourceFormat,
formatOptions,
rest
),
]);
const images = [...artDirectedImages, mainImage];
const uuid = crypto.randomBytes(4).toString("hex").toUpperCase();
const returnObject = {
uuid,
images,
};
imagesData.set(hash, returnObject)
return returnObject;
}

View File

@ -3,8 +3,9 @@ import getSrcset from "./getSrcset.js";
import getConfigOptions from "./getConfigOptions.js";
import getFallbackImage from "./getFallbackImage.js";
import pMap from "p-map";
import { DEFAULT_IO_DELAY } from "../../constants.js";
function delay(ms = 150) {
function delay(ms = DEFAULT_IO_DELAY) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

View File

@ -6,28 +6,32 @@ import { getSrcPath } from "./getSrcPath.js";
import getResolvedSrc from "./getResolvedSrc.js";
import { cwd, sharp } from "../../utils/runtimeChecks.js";
import throwErrorIfUnsupported from "./throwErrorIfUnsupported.js";
import { retryAsync } from "ts-retry";
import { DEFAULT_IO_DELAY } from "../../constants.js";
const { getImageDetails } = await (sharp
? import("./imagetools.js")
: import("./codecs.js"));
export default async function getProcessedImage(src, transformConfigs) {
throwErrorIfUnsupported(src, extname(src).slice(1));
export async function _getProcessedImage(src, transformConfigs) {
throwErrorIfUnsupported(src, extname(src).slice(1));
let base;
if (src.match("(http://|https://|data:image/).*")) {
({ src, base } = await getResolvedSrc(src))
({ src, base } = await getResolvedSrc(src));
} else {
const {
default: { isSsrBuild },
} = await import("../../astroViteConfigs.js")
} = await import("../../astroViteConfigs.js");
if (isSsrBuild) {
const filename = fileURLToPath(import.meta.url)
const assetPath = resolve(filename, "../../client") + src
const filename = fileURLToPath(import.meta.url);
const assetPath = resolve(filename, "../../client") + src;
src = "/" + relative(cwd, assetPath);
}
}
const {
w,
h,
@ -57,3 +61,8 @@ export default async function getProcessedImage(src, transformConfigs) {
imageFormat,
};
}
export default async function getProcessedImage(src, transformConfigs) {
//@todo : hiccups in vips/sharp
return retryAsync(() => _getProcessedImage(src, transformConfigs), { delay: DEFAULT_IO_DELAY, maxTry: 3 })
}

View File

@ -13,9 +13,7 @@ const { fileTypeFromBuffer } = await import("file-type");
export default async function getResolvedSrc(src) {
const token = crypto.createHash("md5").update(src).digest("hex");
let filepath = fsCachePath + token;
const fileExists = (() => {
for (const type of supportedImageTypes) {
const fileExists = fs.existsSync(filepath + `.${type}`);
@ -28,23 +26,23 @@ export default async function getResolvedSrc(src) {
}
})();
if (!fileExists) {
const buffer = Buffer.from(await (await fetch(src)).arrayBuffer());
try {
if (!fileExists) {
const buffer = Buffer.from(await (await fetch(src)).arrayBuffer());
const { ext } = (await fileTypeFromBuffer(buffer)) || {};
throwErrorIfUnsupported(src, ext);
filepath += `.${ext}`;
fs.writeFileSync(filepath, buffer);
}
const base = /^https?:/.test(src)
? parse(new URL(src).pathname).name
: undefined;
const { ext } = (await fileTypeFromBuffer(buffer)) || {};
src = join("/", relative(cwd, filepath));
throwErrorIfUnsupported(src, ext);
filepath += `.${ext}`;
fs.writeFileSync(filepath, buffer);
return { src, base };
} catch (e) {
console.error(`Error while resolving src: ${src} : ${e.message}`)
return null
}
const base = /^https?:/.test(src)
? parse(new URL(src).pathname).name
: undefined;
src = join("/", relative(cwd, filepath));
return { src, base };
}

View File

@ -0,0 +1 @@
export const DEFAULT_IO_DELAY = 350;

View File

@ -5,6 +5,7 @@ import { posix as path, resolve } from "node:path"
import { saveAndCopyAsset } from "./utils/saveAndCopyAsset.js"
import vitePluginAstroImageTools, { store } from "../plugin/index.js"
import pMap from "p-map"
import { DEFAULT_IO_DELAY } from "../constants.js"
const filename = fileURLToPath(import.meta.url);
const astroViteConfigsPath = resolve(filename, "../../astroViteConfigs.js");
@ -60,7 +61,7 @@ export default {
assetPaths,
async ([assetPath, { hash, image, buffer }]) => {
// delay, otherwise unknown errors occur (sharp/vips)
await new Promise((resolve) => setTimeout(resolve, 150));
await new Promise((resolve) => setTimeout(resolve, DEFAULT_IO_DELAY));
try {
await saveAndCopyAsset(
hash,

View File

@ -36,7 +36,7 @@ export const PRODUCTS_TARGET = (lang) => `./content/${lang}/products`
// Product assets
export const ASSETS_LOCALE = true
export const ASSETS_LOCAL = false
// OSRL - Language
export const IS_DEV = true

View File

@ -14,7 +14,7 @@ import { sync as mv } from '@polymech/fs/move'
import { logger } from '@/base/index.js'
import { removeArrayValues, removeArrays, removeBufferValues, removeEmptyObjects } from '@/base/objects.js'
import { ITEM_ASSET_URL, PRODUCT_CONFIG, PRODUCT_ROOT, DEFAULT_IMAGE_URL, ASSETS_LOCALE } from '../app/config.js'
import { ITEM_ASSET_URL, PRODUCT_CONFIG, PRODUCT_ROOT, DEFAULT_IMAGE_URL, ASSETS_LOCAL } from '../app/config.js'
import { GalleryImage, MetaJSON } from './images.js'
import { validateFilename, sanitizeFilename } from "@polymech/fs/utils"
@ -138,7 +138,7 @@ export const gallery = async (
))
}
if (!ASSETS_LOCALE) {
if (!ASSETS_LOCAL) {
galleryFiles = await pMap(galleryFiles, async (f) => (await default_filter(assetUrl(f))) ? f : null, { concurrency: 5 })
galleryFiles = galleryFiles.filter((f) => f !== null)
galleryFiles = default_sort(galleryFiles)
@ -181,7 +181,7 @@ export const gallery = async (
delete imageMeta.exif.icc
delete imageMeta.exif.xmp
delete imageMeta.exif.iptc
const src = ASSETS_LOCALE ? filePath : await image_url(assetUrl(file))
const src = ASSETS_LOCAL ? filePath : await image_url(assetUrl(file))
const ret: GalleryImage =
{
name: path.parse(file).name,